@neus/sdk 1.0.2 → 1.0.4

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/utils.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -29,7 +30,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
30
  // utils.js
30
31
  var utils_exports = {};
31
32
  __export(utils_exports, {
33
+ DEFAULT_HOSTED_VERIFY_URL: () => DEFAULT_HOSTED_VERIFY_URL,
32
34
  NEUS_CONSTANTS: () => NEUS_CONSTANTS,
35
+ PORTABLE_PROOF_SIGNER_HEADER: () => PORTABLE_PROOF_SIGNER_HEADER,
33
36
  StatusPoller: () => StatusPoller,
34
37
  buildVerificationRequest: () => buildVerificationRequest,
35
38
  computeContentHash: () => computeContentHash,
@@ -39,14 +42,22 @@ __export(utils_exports, {
39
42
  deriveDid: () => deriveDid,
40
43
  formatTimestamp: () => formatTimestamp,
41
44
  formatVerificationStatus: () => formatVerificationStatus,
45
+ getHostedCheckoutUrl: () => getHostedCheckoutUrl,
42
46
  isFailureStatus: () => isFailureStatus,
43
47
  isSuccessStatus: () => isSuccessStatus,
44
48
  isSupportedChain: () => isSupportedChain,
45
49
  isTerminalStatus: () => isTerminalStatus,
46
50
  normalizeAddress: () => normalizeAddress,
51
+ resolveDID: () => resolveDID,
52
+ resolveZkPassportConfig: () => resolveZkPassportConfig,
53
+ signMessage: () => signMessage,
54
+ standardizeVerificationRequest: () => standardizeVerificationRequest,
55
+ toAgentDelegationMaxSpend: () => toAgentDelegationMaxSpend,
56
+ toHexUtf8: () => toHexUtf8,
47
57
  validateQHash: () => validateQHash,
48
58
  validateSignatureComponents: () => validateSignatureComponents,
49
59
  validateTimestamp: () => validateTimestamp,
60
+ validateUniversalAddress: () => validateUniversalAddress,
50
61
  validateVerifierPayload: () => validateVerifierPayload,
51
62
  validateWalletAddress: () => validateWalletAddress,
52
63
  withRetry: () => withRetry
@@ -120,21 +131,77 @@ var ValidationError = class extends SDKError {
120
131
  };
121
132
 
122
133
  // utils.js
134
+ var PORTABLE_PROOF_SIGNER_HEADER = "Portable Proof Verification Request";
135
+ var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
136
+ function encodeBase58Bytes(input) {
137
+ let source;
138
+ if (input instanceof Uint8Array) {
139
+ source = input;
140
+ } else if (input instanceof ArrayBuffer) {
141
+ source = new Uint8Array(input);
142
+ } else if (ArrayBuffer.isView(input)) {
143
+ source = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
144
+ } else if (typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(input)) {
145
+ source = new Uint8Array(input);
146
+ } else {
147
+ throw new SDKError("Unsupported non-EVM signature byte format", "INVALID_SIGNATURE_FORMAT");
148
+ }
149
+ if (source.length === 0) return "";
150
+ let zeroes = 0;
151
+ while (zeroes < source.length && source[zeroes] === 0) {
152
+ zeroes++;
153
+ }
154
+ const iFactor = Math.log(256) / Math.log(58);
155
+ const size = (source.length - zeroes) * iFactor + 1 >>> 0;
156
+ const b58 = new Uint8Array(size);
157
+ let length = 0;
158
+ for (let i = zeroes; i < source.length; i++) {
159
+ let carry = source[i];
160
+ let j = 0;
161
+ for (let k = size - 1; (carry !== 0 || j < length) && k >= 0; k--, j++) {
162
+ carry += 256 * b58[k];
163
+ b58[k] = carry % 58;
164
+ carry = carry / 58 | 0;
165
+ }
166
+ length = j;
167
+ }
168
+ let it = size - length;
169
+ while (it < size && b58[it] === 0) {
170
+ it++;
171
+ }
172
+ let out = BASE58_ALPHABET[0].repeat(zeroes);
173
+ for (; it < size; it++) {
174
+ out += BASE58_ALPHABET[b58[it]];
175
+ }
176
+ return out;
177
+ }
123
178
  function deterministicStringify(obj) {
124
179
  if (obj === null || obj === void 0) {
125
180
  return JSON.stringify(obj);
126
181
  }
127
182
  if (typeof obj !== "object") {
183
+ if (typeof obj === "string") return JSON.stringify(obj.normalize("NFC"));
128
184
  return JSON.stringify(obj);
129
185
  }
130
186
  if (Array.isArray(obj)) {
131
- return "[" + obj.map((item) => deterministicStringify(item)).join(",") + "]";
187
+ return `[${obj.map((item) => item === void 0 ? "null" : deterministicStringify(item)).join(",")}]`;
132
188
  }
133
- const sortedKeys = Object.keys(obj).sort();
189
+ const sortedKeys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
134
190
  const pairs = sortedKeys.map(
135
- (key) => JSON.stringify(key) + ":" + deterministicStringify(obj[key])
191
+ (key) => `${JSON.stringify(key)}:${deterministicStringify(obj[key])}`
136
192
  );
137
- return "{" + pairs.join(",") + "}";
193
+ return `{${pairs.join(",")}}`;
194
+ }
195
+ function chainLineForPortableProofSigner(chain, chainId) {
196
+ if (typeof chain === "string" && chain.length > 0) {
197
+ const m = chain.match(/^eip155:(\d+)$/);
198
+ if (m) return Number(m[1]);
199
+ return chain;
200
+ }
201
+ if (typeof chainId === "number" && Number.isFinite(chainId) && chainId > 0) {
202
+ return chainId;
203
+ }
204
+ throw new SDKError("chainId is required (or provide chain for universal mode)", "INVALID_CHAIN_CONTEXT");
138
205
  }
139
206
  function constructVerificationMessage({ walletAddress, signedTimestamp, data, verifierIds, chainId, chain }) {
140
207
  if (!walletAddress || typeof walletAddress !== "string") {
@@ -149,28 +216,28 @@ function constructVerificationMessage({ walletAddress, signedTimestamp, data, ve
149
216
  if (!Array.isArray(verifierIds) || verifierIds.length === 0) {
150
217
  throw new SDKError("verifierIds is required and must be a non-empty array", "INVALID_VERIFIER_IDS");
151
218
  }
152
- const chainContext = typeof chain === "string" && chain.length > 0 ? chain : chainId;
153
- if (!chainContext) {
219
+ if ((typeof chain !== "string" || !chain.length) && !(typeof chainId === "number" && chainId > 0)) {
154
220
  throw new SDKError("chainId is required (or provide chain for universal mode)", "INVALID_CHAIN_CONTEXT");
155
221
  }
156
- if (chainContext === chainId && typeof chainId !== "number") {
157
- throw new SDKError("chainId must be a number when provided", "INVALID_CHAIN_ID");
158
- }
159
- if (chainContext === chain && (typeof chain !== "string" || !chain.includes(":"))) {
222
+ if (typeof chain === "string" && chain.length > 0 && !chain.includes(":")) {
160
223
  throw new SDKError('chain must be a "namespace:reference" string', "INVALID_CHAIN");
161
224
  }
225
+ if ((!chain || !chain.length) && typeof chainId !== "number") {
226
+ throw new SDKError("chainId must be a number when provided", "INVALID_CHAIN_ID");
227
+ }
228
+ const chainLine = chainLineForPortableProofSigner(chain, chainId);
162
229
  const namespace = typeof chain === "string" && chain.includes(":") ? chain.split(":")[0] : "eip155";
163
230
  const normalizedWalletAddress = namespace === "eip155" ? walletAddress.toLowerCase() : walletAddress;
164
231
  const dataString = deterministicStringify(data);
165
232
  const messageComponents = [
166
- "NEUS Verification Request",
233
+ PORTABLE_PROOF_SIGNER_HEADER,
167
234
  `Wallet: ${normalizedWalletAddress}`,
168
- `Chain: ${chainContext}`,
235
+ `Chain: ${chainLine}`,
169
236
  `Verifiers: ${verifierIds.join(",")}`,
170
237
  `Data: ${dataString}`,
171
238
  `Timestamp: ${signedTimestamp}`
172
239
  ];
173
- return messageComponents.join("\n");
240
+ return messageComponents.join("\n").normalize("NFC");
174
241
  }
175
242
  function validateWalletAddress(address) {
176
243
  if (!address || typeof address !== "string") {
@@ -178,6 +245,25 @@ function validateWalletAddress(address) {
178
245
  }
179
246
  return /^0x[a-fA-F0-9]{40}$/.test(address);
180
247
  }
248
+ function validateUniversalAddress(address, chain) {
249
+ if (!address || typeof address !== "string") return false;
250
+ const value = address.trim();
251
+ if (!value) return false;
252
+ const chainRef = typeof chain === "string" ? chain.trim().toLowerCase() : "";
253
+ const namespace = chainRef.includes(":") ? chainRef.split(":")[0] : "";
254
+ if (validateWalletAddress(value)) return true;
255
+ if (namespace === "eip155") return false;
256
+ if (namespace === "solana") {
257
+ return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(value);
258
+ }
259
+ if (namespace === "bip122") {
260
+ return /^(bc1|tb1|bcrt1)[a-z0-9]{11,87}$/.test(value.toLowerCase()) || /^[13mn2][a-km-zA-HJ-NP-Z1-9]{25,62}$/.test(value);
261
+ }
262
+ if (namespace === "near") {
263
+ return /^[a-z0-9._-]{2,64}$/.test(value);
264
+ }
265
+ return /^[A-Za-z0-9][A-Za-z0-9._:-]{1,127}$/.test(value);
266
+ }
181
267
  function validateTimestamp(timestamp, maxAgeMs = 5 * 60 * 1e3) {
182
268
  if (!timestamp || typeof timestamp !== "number") {
183
269
  return false;
@@ -199,7 +285,7 @@ function createVerificationData(content, owner, reference = null) {
199
285
  };
200
286
  return {
201
287
  content,
202
- owner: owner.toLowerCase(),
288
+ owner: validateWalletAddress(owner) ? owner.toLowerCase() : owner,
203
289
  reference: reference || {
204
290
  // Must be a valid backend enum value; 'content' is not supported.
205
291
  type: "other",
@@ -224,9 +310,234 @@ function deriveDid(address, chainIdOrChain) {
224
310
  return `did:pkh:eip155:${chainContext}:${address.toLowerCase()}`;
225
311
  }
226
312
  }
313
+ async function resolveDID(params, options = {}) {
314
+ const endpointPath = options.endpoint || "/api/v1/profile/did/resolve";
315
+ const apiUrl = typeof options.apiUrl === "string" ? options.apiUrl.trim() : "";
316
+ const resolveEndpoint = (path) => {
317
+ if (!path || typeof path !== "string") return null;
318
+ const trimmedPath = path.trim();
319
+ if (!trimmedPath) return null;
320
+ if (/^https?:\/\//i.test(trimmedPath)) return trimmedPath;
321
+ if (trimmedPath.startsWith("/")) {
322
+ if (!apiUrl) return trimmedPath;
323
+ try {
324
+ return new URL(trimmedPath, apiUrl.endsWith("/") ? apiUrl : `${apiUrl}/`).toString();
325
+ } catch {
326
+ return null;
327
+ }
328
+ }
329
+ const base = apiUrl || NEUS_CONSTANTS.API_BASE_URL;
330
+ if (!base || typeof base !== "string") return null;
331
+ try {
332
+ return new URL(trimmedPath, base.endsWith("/") ? base : `${base}/`).toString();
333
+ } catch {
334
+ return null;
335
+ }
336
+ };
337
+ const endpoint = resolveEndpoint(endpointPath);
338
+ if (!endpoint) {
339
+ throw new SDKError("resolveDID requires a valid endpoint", "INVALID_ENDPOINT");
340
+ }
341
+ const payload = {
342
+ walletAddress: params?.walletAddress,
343
+ chainId: params?.chainId,
344
+ chain: params?.chain
345
+ };
346
+ const isRelative = endpoint.startsWith("/") || !/^https?:\/\//i.test(endpoint);
347
+ const credentialsMode = options.credentials !== void 0 ? options.credentials : isRelative ? "same-origin" : "omit";
348
+ try {
349
+ const response = await fetch(endpoint, {
350
+ method: "POST",
351
+ headers: {
352
+ "Content-Type": "application/json",
353
+ Accept: "application/json",
354
+ ...options.headers || {}
355
+ },
356
+ body: JSON.stringify(payload),
357
+ credentials: credentialsMode
358
+ });
359
+ const json = await response.json().catch(() => null);
360
+ if (!response.ok) {
361
+ const msg = json?.error?.message || json?.error || json?.message || "DID resolution failed";
362
+ throw new SDKError(msg, "DID_RESOLVE_FAILED", json);
363
+ }
364
+ const did = json?.data?.did || json?.did;
365
+ if (!did || typeof did !== "string") {
366
+ throw new SDKError("DID resolution missing DID", "DID_RESOLVE_MISSING", json);
367
+ }
368
+ return { did, data: json?.data || null, raw: json };
369
+ } catch (error) {
370
+ if (error instanceof SDKError) throw error;
371
+ throw new SDKError(`DID resolution failed: ${error?.message || error}`, "DID_RESOLVE_FAILED");
372
+ }
373
+ }
374
+ async function standardizeVerificationRequest(params, options = {}) {
375
+ const endpointPath = options.endpoint || "/api/v1/verification/standardize";
376
+ const apiUrl = typeof options.apiUrl === "string" ? options.apiUrl.trim() : "";
377
+ const resolveEndpoint = (path) => {
378
+ if (!path || typeof path !== "string") return null;
379
+ const trimmedPath = path.trim();
380
+ if (!trimmedPath) return null;
381
+ if (/^https?:\/\//i.test(trimmedPath)) return trimmedPath;
382
+ if (trimmedPath.startsWith("/")) {
383
+ if (!apiUrl) return trimmedPath;
384
+ try {
385
+ return new URL(trimmedPath, apiUrl.endsWith("/") ? apiUrl : `${apiUrl}/`).toString();
386
+ } catch {
387
+ return null;
388
+ }
389
+ }
390
+ const base = apiUrl || NEUS_CONSTANTS.API_BASE_URL;
391
+ if (!base || typeof base !== "string") return null;
392
+ try {
393
+ return new URL(trimmedPath, base.endsWith("/") ? base : `${base}/`).toString();
394
+ } catch {
395
+ return null;
396
+ }
397
+ };
398
+ const endpoint = resolveEndpoint(endpointPath);
399
+ if (!endpoint) {
400
+ throw new SDKError("standardizeVerificationRequest requires a valid endpoint", "INVALID_ENDPOINT");
401
+ }
402
+ const isRelative = endpoint.startsWith("/") || !/^https?:\/\//i.test(endpoint);
403
+ const credentialsMode = options.credentials !== void 0 ? options.credentials : isRelative ? "same-origin" : "omit";
404
+ try {
405
+ const response = await fetch(endpoint, {
406
+ method: "POST",
407
+ headers: {
408
+ "Content-Type": "application/json",
409
+ Accept: "application/json",
410
+ ...options.headers || {}
411
+ },
412
+ body: JSON.stringify(params || {}),
413
+ credentials: credentialsMode
414
+ });
415
+ const json = await response.json().catch(() => null);
416
+ if (!response.ok) {
417
+ const msg = json?.error?.message || json?.error || json?.message || "Standardize request failed";
418
+ throw new SDKError(msg, "STANDARDIZE_FAILED", json);
419
+ }
420
+ return json?.data || json;
421
+ } catch (error) {
422
+ if (error instanceof SDKError) throw error;
423
+ throw new SDKError(`Standardize request failed: ${error?.message || error}`, "STANDARDIZE_FAILED");
424
+ }
425
+ }
426
+ function resolveZkPassportConfig(overrides = {}) {
427
+ const defaults = {
428
+ provider: "zkpassport",
429
+ scope: "basic_kyc",
430
+ checkSanctions: true,
431
+ requireFaceMatch: true,
432
+ faceMatchMode: "strict"
433
+ };
434
+ return {
435
+ ...defaults,
436
+ ...overrides && typeof overrides === "object" ? overrides : {}
437
+ };
438
+ }
439
+ function toHexUtf8(value) {
440
+ const input = typeof value === "string" ? value : String(value || "");
441
+ const bytes = new TextEncoder().encode(input);
442
+ return `0x${Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("")}`;
443
+ }
444
+ async function signMessage({ provider, message, walletAddress, chain } = {}) {
445
+ const msg = typeof message === "string" ? message : String(message || "");
446
+ if (!msg) {
447
+ throw new SDKError("signMessage: message is required", "INVALID_ARGUMENT");
448
+ }
449
+ const resolvedProvider = provider || (typeof window !== "undefined" && window?.ethereum ? window.ethereum : null);
450
+ if (!resolvedProvider) {
451
+ throw new SDKError("signMessage: provider is required", "SIGNER_UNAVAILABLE");
452
+ }
453
+ const chainStr = typeof chain === "string" && chain.trim().length > 0 ? chain.trim() : "eip155";
454
+ const namespace = chainStr.includes(":") ? chainStr.split(":")[0] || "eip155" : "eip155";
455
+ const resolveAddress = async () => {
456
+ if (typeof walletAddress === "string" && walletAddress.trim().length > 0) return walletAddress;
457
+ if (namespace === "solana") {
458
+ if (resolvedProvider?.publicKey && typeof resolvedProvider.publicKey.toBase58 === "function") {
459
+ const pk = resolvedProvider.publicKey.toBase58();
460
+ if (typeof pk === "string" && pk) return pk;
461
+ }
462
+ if (typeof resolvedProvider.getAddress === "function") {
463
+ const addr = await resolvedProvider.getAddress().catch(() => null);
464
+ if (typeof addr === "string" && addr) return addr;
465
+ }
466
+ if (typeof resolvedProvider.address === "string" && resolvedProvider.address) return resolvedProvider.address;
467
+ return null;
468
+ }
469
+ if (typeof resolvedProvider.address === "string" && resolvedProvider.address) return resolvedProvider.address;
470
+ if (typeof resolvedProvider.getAddress === "function") return resolvedProvider.getAddress();
471
+ if (typeof resolvedProvider.request === "function") {
472
+ let accounts = await resolvedProvider.request({ method: "eth_accounts" }).catch(() => []);
473
+ if (!Array.isArray(accounts) || accounts.length === 0) {
474
+ accounts = await resolvedProvider.request({ method: "eth_requestAccounts" }).catch(() => []);
475
+ }
476
+ if (Array.isArray(accounts) && accounts[0]) return accounts[0];
477
+ }
478
+ return null;
479
+ };
480
+ if (namespace !== "eip155") {
481
+ if (typeof resolvedProvider.signMessage === "function") {
482
+ const encoded = typeof msg === "string" ? new TextEncoder().encode(msg) : msg;
483
+ const result = await resolvedProvider.signMessage(encoded);
484
+ if (typeof result === "string" && result) return result;
485
+ if (result instanceof Uint8Array) return encodeBase58Bytes(result);
486
+ if (result instanceof ArrayBuffer) return encodeBase58Bytes(new Uint8Array(result));
487
+ if (ArrayBuffer.isView(result)) return encodeBase58Bytes(result);
488
+ if (typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(result)) return encodeBase58Bytes(result);
489
+ }
490
+ throw new SDKError("Non-EVM signing requires provider.signMessage", "SIGNER_UNAVAILABLE");
491
+ }
492
+ const address = await resolveAddress();
493
+ if (typeof resolvedProvider.request === "function" && address) {
494
+ let firstPersonalSignError = null;
495
+ try {
496
+ const sig = await resolvedProvider.request({ method: "personal_sign", params: [msg, address] });
497
+ if (typeof sig === "string" && sig) return sig;
498
+ } catch (error) {
499
+ firstPersonalSignError = error;
500
+ }
501
+ let secondPersonalSignError = null;
502
+ try {
503
+ const sig = await resolvedProvider.request({ method: "personal_sign", params: [address, msg] });
504
+ if (typeof sig === "string" && sig) return sig;
505
+ } catch (error) {
506
+ secondPersonalSignError = error;
507
+ const signatureErrorMessage = String(
508
+ error?.message || error?.reason || firstPersonalSignError?.message || firstPersonalSignError?.reason || ""
509
+ ).toLowerCase();
510
+ const needsHex = /byte|bytes|invalid byte sequence|encoding|non-hex/i.test(signatureErrorMessage);
511
+ if (needsHex) {
512
+ try {
513
+ const hexMsg = toHexUtf8(msg);
514
+ const sig = await resolvedProvider.request({ method: "personal_sign", params: [hexMsg, address] });
515
+ if (typeof sig === "string" && sig) return sig;
516
+ } catch {
517
+ }
518
+ }
519
+ }
520
+ try {
521
+ const sig = await resolvedProvider.request({ method: "eth_sign", params: [address, msg] });
522
+ if (typeof sig === "string" && sig) return sig;
523
+ } catch {
524
+ }
525
+ if (secondPersonalSignError || firstPersonalSignError) {
526
+ const lastError = secondPersonalSignError || firstPersonalSignError;
527
+ const isUserRejection = [4001, "ACTION_REJECTED"].includes(lastError?.code);
528
+ if (isUserRejection) {
529
+ throw lastError;
530
+ }
531
+ }
532
+ }
533
+ if (typeof resolvedProvider.signMessage === "function") {
534
+ const result = await resolvedProvider.signMessage(msg);
535
+ if (typeof result === "string" && result) return result;
536
+ }
537
+ throw new SDKError("Unable to sign message with provided wallet/provider", "SIGNER_UNAVAILABLE");
538
+ }
227
539
  function isTerminalStatus(status) {
228
- if (!status || typeof status !== "string")
229
- return false;
540
+ if (!status || typeof status !== "string") return false;
230
541
  const successStates = [
231
542
  "verified",
232
543
  "verified_no_verifiers",
@@ -247,8 +558,7 @@ function isTerminalStatus(status) {
247
558
  return successStates.includes(status) || failureStates.includes(status);
248
559
  }
249
560
  function isSuccessStatus(status) {
250
- if (!status || typeof status !== "string")
251
- return false;
561
+ if (!status || typeof status !== "string") return false;
252
562
  const successStates = [
253
563
  "verified",
254
564
  "verified_no_verifiers",
@@ -259,8 +569,7 @@ function isSuccessStatus(status) {
259
569
  return successStates.includes(status);
260
570
  }
261
571
  function isFailureStatus(status) {
262
- if (!status || typeof status !== "string")
263
- return false;
572
+ if (!status || typeof status !== "string") return false;
264
573
  const failureStates = [
265
574
  "rejected",
266
575
  "rejected_verifier_failure",
@@ -407,7 +716,7 @@ var StatusPoller = class {
407
716
  const pollAttempt = async () => {
408
717
  try {
409
718
  this.attempt++;
410
- const response = await this.client.getStatus(this.qHash);
719
+ const response = await this.client.getProof(this.qHash);
411
720
  if (isTerminalStatus(response.status)) {
412
721
  resolve(response);
413
722
  return;
@@ -452,7 +761,7 @@ var StatusPoller = class {
452
761
  }
453
762
  };
454
763
  var NEUS_CONSTANTS = {
455
- // Hub chain (where all verifications occur)
764
+ /** Default EVM chain id for NEUS protocol signing context (`HUB_CHAIN_ID` name kept for compatibility). */
456
765
  HUB_CHAIN_ID: 84532,
457
766
  // Supported target chains for cross-chain propagation
458
767
  TESTNET_CHAINS: [
@@ -506,23 +815,20 @@ function validateVerifierPayload(verifierId, data) {
506
815
  const id = verifierId.replace(/@\d+$/, "");
507
816
  if (id === "nft-ownership") {
508
817
  ["contractAddress", "tokenId", "chainId"].forEach((key) => {
509
- if (!(key in data))
510
- result.missing.push(key);
818
+ if (!(key in data)) result.missing.push(key);
511
819
  });
512
820
  if (!("ownerAddress" in data)) {
513
- result.warnings.push("ownerAddress omitted (most deployments default to the signed walletAddress)");
821
+ result.warnings.push("ownerAddress omitted (defaults to the signed walletAddress)");
514
822
  }
515
823
  } else if (id === "token-holding") {
516
824
  ["contractAddress", "minBalance", "chainId"].forEach((key) => {
517
- if (!(key in data))
518
- result.missing.push(key);
825
+ if (!(key in data)) result.missing.push(key);
519
826
  });
520
827
  if (!("ownerAddress" in data)) {
521
- result.warnings.push("ownerAddress omitted (most deployments default to the signed walletAddress)");
828
+ result.warnings.push("ownerAddress omitted (defaults to the signed walletAddress)");
522
829
  }
523
830
  } else if (id === "ownership-basic") {
524
- if (!("owner" in data))
525
- result.missing.push("owner");
831
+ if (!("owner" in data)) result.missing.push("owner");
526
832
  const hasContent = typeof data.content === "string" && data.content.length > 0;
527
833
  const hasContentHash = typeof data.contentHash === "string" && data.contentHash.length > 0;
528
834
  const hasRefId = typeof data.reference?.id === "string" && data.reference.id.length > 0;
@@ -586,8 +892,7 @@ async function withRetry(fn, options = {}) {
586
892
  return await fn();
587
893
  } catch (error) {
588
894
  lastError = error;
589
- if (attempt === maxAttempts)
590
- break;
895
+ if (attempt === maxAttempts) break;
591
896
  const delayMs = Math.min(
592
897
  baseDelay * Math.pow(backoffFactor, attempt - 1),
593
898
  maxDelay
@@ -655,9 +960,72 @@ function validateSignatureComponents({ walletAddress, signature, signedTimestamp
655
960
  }
656
961
  return result;
657
962
  }
963
+ function toAgentDelegationMaxSpend(humanAmount, decimals) {
964
+ if (humanAmount === void 0 || humanAmount === null) {
965
+ throw new ValidationError("humanAmount is required", "humanAmount", humanAmount);
966
+ }
967
+ const s0 = String(humanAmount).trim();
968
+ if (!s0) {
969
+ throw new ValidationError("humanAmount must be non-empty", "humanAmount", humanAmount);
970
+ }
971
+ if (s0.startsWith("-") || s0.startsWith("+")) {
972
+ throw new ValidationError("humanAmount must be non-negative", "humanAmount", humanAmount);
973
+ }
974
+ const d = Number(decimals);
975
+ if (!Number.isInteger(d) || d < 0 || d > 78) {
976
+ throw new ValidationError("decimalPlaces must be an integer from 0 to 78", "decimals", decimals);
977
+ }
978
+ if (!/^(?:\d+\.?\d*|\.\d+)$/.test(s0)) {
979
+ throw new ValidationError(
980
+ 'humanAmount must be a decimal string (e.g. "100" or "100.50")',
981
+ "humanAmount",
982
+ humanAmount
983
+ );
984
+ }
985
+ const dot = s0.indexOf(".");
986
+ const intPart = dot === -1 ? s0 : s0.slice(0, dot);
987
+ const fracRaw = dot === -1 ? "" : s0.slice(dot + 1);
988
+ const intNormalized = intPart === "" ? "0" : (() => {
989
+ const s = intPart.replace(/^0+/, "");
990
+ return s === "" ? "0" : s;
991
+ })();
992
+ if (!/^\d+$/.test(intNormalized)) {
993
+ throw new ValidationError("humanAmount has an invalid integer part", "humanAmount", humanAmount);
994
+ }
995
+ if (fracRaw && !/^\d*$/.test(fracRaw)) {
996
+ throw new ValidationError("humanAmount has an invalid fractional part", "humanAmount", humanAmount);
997
+ }
998
+ const fracPadded = `${fracRaw}${"0".repeat(d)}`.slice(0, d);
999
+ const base = BigInt(10) ** BigInt(d);
1000
+ const value = BigInt(intNormalized) * base + BigInt(fracPadded || "0");
1001
+ const out = value.toString();
1002
+ if (out.length > 78) {
1003
+ throw new ValidationError("maxSpend exceeds 78-digit limit after conversion", "humanAmount", humanAmount);
1004
+ }
1005
+ return out;
1006
+ }
1007
+ var DEFAULT_HOSTED_VERIFY_URL = "https://neus.network/verify";
1008
+ function getHostedCheckoutUrl(opts = {}) {
1009
+ const base = typeof opts.baseUrl === "string" && opts.baseUrl.trim() ? opts.baseUrl.replace(/\/+$/, "") : DEFAULT_HOSTED_VERIFY_URL;
1010
+ const params = new URLSearchParams();
1011
+ if (opts.gateId) params.set("gateId", String(opts.gateId));
1012
+ if (opts.returnUrl) params.set("returnUrl", String(opts.returnUrl));
1013
+ if (Array.isArray(opts.verifiers) && opts.verifiers.length > 0) {
1014
+ params.set("verifiers", opts.verifiers.filter(Boolean).join(","));
1015
+ }
1016
+ if (opts.preset) params.set("preset", String(opts.preset));
1017
+ if (opts.mode) params.set("mode", String(opts.mode));
1018
+ if (opts.intent) params.set("intent", String(opts.intent));
1019
+ if (opts.origin) params.set("origin", String(opts.origin));
1020
+ if (opts.oauthProvider) params.set("oauthProvider", String(opts.oauthProvider));
1021
+ const qs = params.toString();
1022
+ return qs ? `${base}?${qs}` : base;
1023
+ }
658
1024
  // Annotate the CommonJS export names for ESM import in node:
659
1025
  0 && (module.exports = {
1026
+ DEFAULT_HOSTED_VERIFY_URL,
660
1027
  NEUS_CONSTANTS,
1028
+ PORTABLE_PROOF_SIGNER_HEADER,
661
1029
  StatusPoller,
662
1030
  buildVerificationRequest,
663
1031
  computeContentHash,
@@ -667,14 +1035,22 @@ function validateSignatureComponents({ walletAddress, signature, signedTimestamp
667
1035
  deriveDid,
668
1036
  formatTimestamp,
669
1037
  formatVerificationStatus,
1038
+ getHostedCheckoutUrl,
670
1039
  isFailureStatus,
671
1040
  isSuccessStatus,
672
1041
  isSupportedChain,
673
1042
  isTerminalStatus,
674
1043
  normalizeAddress,
1044
+ resolveDID,
1045
+ resolveZkPassportConfig,
1046
+ signMessage,
1047
+ standardizeVerificationRequest,
1048
+ toAgentDelegationMaxSpend,
1049
+ toHexUtf8,
675
1050
  validateQHash,
676
1051
  validateSignatureComponents,
677
1052
  validateTimestamp,
1053
+ validateUniversalAddress,
678
1054
  validateVerifierPayload,
679
1055
  validateWalletAddress,
680
1056
  withRetry
package/cli/neus.mjs ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+ const argv = process.argv.slice(2);
3
+ const sub = argv[0];
4
+
5
+ function usage() {
6
+ process.stderr.write("Usage: neus init\n");
7
+ process.stderr.write("Prints hosted MCP config and doc URLs. Does not write files.\n");
8
+ process.exit(sub && sub !== "help" && sub !== "--help" && sub !== "-h" ? 1 : 0);
9
+ }
10
+
11
+ function printInit() {
12
+ const mcpBlock = {
13
+ mcpServers: {
14
+ neus: {
15
+ type: "streamableHttp",
16
+ url: "https://mcp.neus.network/mcp",
17
+ },
18
+ },
19
+ };
20
+
21
+ const lines = [
22
+ "# NEUS",
23
+ "",
24
+ "## MCP",
25
+ JSON.stringify(mcpBlock, null, 2),
26
+ "",
27
+ "## URLs",
28
+ "MCP: https://mcp.neus.network/mcp",
29
+ "Verify: https://neus.network/verify",
30
+ "Explorer: https://neus.network/hub",
31
+ "",
32
+ "## Docs",
33
+ "MCP setup: https://docs.neus.network/mcp/setup",
34
+ "LLM / assistants: https://docs.neus.network/platform/llm-docs",
35
+ "Agents: https://docs.neus.network/agents/overview",
36
+ "Agent identity: https://docs.neus.network/agents/agent-identity",
37
+ "Agent delegation: https://docs.neus.network/agents/agent-delegation",
38
+ "Integration: https://docs.neus.network/integration",
39
+ "Quickstart: https://docs.neus.network/quickstart",
40
+ "Machine route map: https://neus.network/llms.txt",
41
+ "",
42
+ "This command only prints to stdout; it does not modify files or create accounts.",
43
+ "Use Authorization: Bearer <access key> when a tool returns auth_required (see MCP auth).",
44
+ ];
45
+
46
+ process.stdout.write(`${lines.join("\n")}\n`);
47
+ }
48
+
49
+ if (!sub || sub === "help" || sub === "--help" || sub === "-h") {
50
+ usage();
51
+ }
52
+
53
+ if (sub === "init") {
54
+ printInit();
55
+ process.exit(0);
56
+ }
57
+
58
+ usage();