@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/README.md +53 -75
- package/SECURITY.md +33 -29
- package/cjs/client.cjs +678 -337
- package/cjs/errors.cjs +1 -0
- package/cjs/gates.cjs +1 -0
- package/cjs/index.cjs +927 -362
- package/cjs/utils.cjs +408 -32
- package/cli/neus.mjs +58 -0
- package/client.js +1957 -1728
- package/errors.js +5 -5
- package/gates.js +18 -18
- package/index.js +18 -3
- package/neus-logo.svg +3 -0
- package/package.json +21 -11
- package/types.d.ts +303 -53
- package/utils.js +1291 -777
- package/widgets/README.md +12 -20
- package/widgets/index.js +9 -9
- package/widgets/verify-gate/dist/ProofBadge.js +57 -52
- package/widgets/verify-gate/dist/VerifyGate.js +357 -121
- package/widgets/verify-gate/index.js +13 -13
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
|
|
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)
|
|
191
|
+
(key) => `${JSON.stringify(key)}:${deterministicStringify(obj[key])}`
|
|
136
192
|
);
|
|
137
|
-
return
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
233
|
+
PORTABLE_PROOF_SIGNER_HEADER,
|
|
167
234
|
`Wallet: ${normalizedWalletAddress}`,
|
|
168
|
-
`Chain: ${
|
|
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.
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
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();
|