@neus/sdk 1.0.12 → 1.1.1
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 +206 -208
- package/cjs/client.cjs +191 -22
- package/cjs/errors.cjs +2 -35
- package/cjs/gates.cjs +1 -21
- package/cjs/index.cjs +203 -22
- package/cjs/utils.cjs +2 -0
- package/cli/neus.mjs +1215 -120
- package/client.js +150 -31
- package/errors.js +154 -189
- package/gates.js +0 -20
- package/index.js +2 -0
- package/package.json +142 -135
- package/sponsor.js +95 -0
- package/types.d.ts +91 -14
- package/utils.js +2 -0
- package/widgets/README.md +1 -1
- package/widgets/verify-gate/dist/ProofBadge.js +8 -16
- package/widgets/verify-gate/dist/VerifyGate.js +28 -15
- package/neus-logo.svg +0 -3
package/client.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ApiError, ValidationError, NetworkError, ConfigurationError } from './errors.js';
|
|
2
|
+
import { fetchSponsorGrant } from './sponsor.js';
|
|
2
3
|
import {
|
|
3
4
|
PORTABLE_PROOF_SIGNER_HEADER,
|
|
4
5
|
constructVerificationMessage,
|
|
@@ -239,6 +240,17 @@ const validateVerifierData = (verifierId, data) => {
|
|
|
239
240
|
if (data.agentType && !['ai', 'bot', 'service', 'automation', 'agent'].includes(data.agentType)) {
|
|
240
241
|
return { valid: false, error: 'agentType must be one of: ai, bot, service, automation, agent' };
|
|
241
242
|
}
|
|
243
|
+
if (data.defaultRuntime && typeof data.defaultRuntime === 'object') {
|
|
244
|
+
if (data.defaultRuntime.provider && typeof data.defaultRuntime.provider === 'string' && data.defaultRuntime.provider.length > 64) {
|
|
245
|
+
return { valid: false, error: 'defaultRuntime.provider must be 64 chars or less' };
|
|
246
|
+
}
|
|
247
|
+
if (data.defaultRuntime.model && typeof data.defaultRuntime.model === 'string' && data.defaultRuntime.model.length > 128) {
|
|
248
|
+
return { valid: false, error: 'defaultRuntime.model must be 128 chars or less' };
|
|
249
|
+
}
|
|
250
|
+
if (data.defaultRuntime.mode && typeof data.defaultRuntime.mode === 'string' && data.defaultRuntime.mode.length > 64) {
|
|
251
|
+
return { valid: false, error: 'defaultRuntime.mode must be 64 chars or less' };
|
|
252
|
+
}
|
|
253
|
+
}
|
|
242
254
|
break;
|
|
243
255
|
case 'agent-delegation':
|
|
244
256
|
if (!data.controllerWallet || !validateWalletAddress(data.controllerWallet)) {
|
|
@@ -253,6 +265,18 @@ const validateVerifierData = (verifierId, data) => {
|
|
|
253
265
|
if (data.expiresAt && (typeof data.expiresAt !== 'number' || data.expiresAt < Date.now())) {
|
|
254
266
|
return { valid: false, error: 'expiresAt must be a future timestamp' };
|
|
255
267
|
}
|
|
268
|
+
if (data.model && typeof data.model === 'string' && data.model.length > 128) {
|
|
269
|
+
return { valid: false, error: 'model must be 128 chars or less' };
|
|
270
|
+
}
|
|
271
|
+
if (data.provider && typeof data.provider === 'string' && data.provider.length > 64) {
|
|
272
|
+
return { valid: false, error: 'provider must be 64 chars or less' };
|
|
273
|
+
}
|
|
274
|
+
if (data.allowedActions && Array.isArray(data.allowedActions) && data.allowedActions.length > 32) {
|
|
275
|
+
return { valid: false, error: 'allowedActions must have 32 items or less' };
|
|
276
|
+
}
|
|
277
|
+
if (data.deniedActions && Array.isArray(data.deniedActions) && data.deniedActions.length > 32) {
|
|
278
|
+
return { valid: false, error: 'deniedActions must have 32 items or less' };
|
|
279
|
+
}
|
|
256
280
|
break;
|
|
257
281
|
case 'ai-content-moderation':
|
|
258
282
|
if (!data.content || typeof data.content !== 'string') {
|
|
@@ -373,6 +397,77 @@ export class NeusClient {
|
|
|
373
397
|
} catch {
|
|
374
398
|
void 0;
|
|
375
399
|
}
|
|
400
|
+
|
|
401
|
+
/** @type {{ token: string, expMs: number, key: string } | null} */
|
|
402
|
+
this._sponsorGrantCache = null;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
_getBillingWallet() {
|
|
406
|
+
const raw =
|
|
407
|
+
this.config.billingWallet ||
|
|
408
|
+
this.config.sponsorOrgWallet ||
|
|
409
|
+
this.config.orgWallet ||
|
|
410
|
+
null;
|
|
411
|
+
if (typeof raw !== 'string') return null;
|
|
412
|
+
const trimmed = raw.trim().toLowerCase();
|
|
413
|
+
return /^0x[a-f0-9]{40}$/.test(trimmed) ? trimmed : null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
_resolveIntegratorOrigin() {
|
|
417
|
+
if (typeof this.config.appOrigin === 'string' && this.config.appOrigin.trim()) {
|
|
418
|
+
return this.config.appOrigin.trim();
|
|
419
|
+
}
|
|
420
|
+
try {
|
|
421
|
+
if (typeof window !== 'undefined' && window.location?.origin) {
|
|
422
|
+
return window.location.origin;
|
|
423
|
+
}
|
|
424
|
+
} catch {
|
|
425
|
+
void 0;
|
|
426
|
+
}
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
async _resolveSponsorGrantHeaders(verifierIds = []) {
|
|
431
|
+
const appId = typeof this.config.appId === 'string' ? this.config.appId.trim() : '';
|
|
432
|
+
const orgWallet = this._getBillingWallet();
|
|
433
|
+
if (!appId || !orgWallet) {
|
|
434
|
+
return {};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const normalizedVerifierIds = Array.isArray(verifierIds)
|
|
438
|
+
? verifierIds.map((v) => String(v || '').trim()).filter(Boolean).slice(0, 25)
|
|
439
|
+
: [];
|
|
440
|
+
const cacheKey = `${appId}:${orgWallet}:${normalizedVerifierIds.join(',')}`;
|
|
441
|
+
const now = Date.now();
|
|
442
|
+
if (
|
|
443
|
+
this._sponsorGrantCache &&
|
|
444
|
+
this._sponsorGrantCache.key === cacheKey &&
|
|
445
|
+
this._sponsorGrantCache.expMs > now + 30_000
|
|
446
|
+
) {
|
|
447
|
+
return { 'X-Sponsor-Grant': this._sponsorGrantCache.token };
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const origin = this._resolveIntegratorOrigin();
|
|
451
|
+
const grant = await fetchSponsorGrant({
|
|
452
|
+
apiUrl: this.baseUrl,
|
|
453
|
+
appId,
|
|
454
|
+
orgWallet,
|
|
455
|
+
verifierIds: normalizedVerifierIds,
|
|
456
|
+
origin
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
const expSeconds = Number(grant?.exp);
|
|
460
|
+
const expMs = Number.isFinite(expSeconds) && expSeconds > 0
|
|
461
|
+
? expSeconds * 1000
|
|
462
|
+
: now + 15 * 60 * 1000;
|
|
463
|
+
|
|
464
|
+
this._sponsorGrantCache = {
|
|
465
|
+
key: cacheKey,
|
|
466
|
+
token: grant.sponsorGrant,
|
|
467
|
+
expMs
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
return { 'X-Sponsor-Grant': grant.sponsorGrant };
|
|
376
471
|
}
|
|
377
472
|
|
|
378
473
|
_getHubChainId() {
|
|
@@ -457,12 +552,12 @@ export class NeusClient {
|
|
|
457
552
|
throw new ConfigurationError('Invalid wallet provider');
|
|
458
553
|
}
|
|
459
554
|
|
|
460
|
-
_getDefaultBrowserWallet() {
|
|
461
|
-
if (typeof window === 'undefined') return null;
|
|
462
|
-
// Legacy convenience fallback only. Non-EVM wallets must be passed explicitly
|
|
463
|
-
// with CAIP-2 chain context so the SDK does not route them through EVM RPC.
|
|
464
|
-
return window.ethereum || null;
|
|
465
|
-
}
|
|
555
|
+
_getDefaultBrowserWallet() {
|
|
556
|
+
if (typeof window === 'undefined') return null;
|
|
557
|
+
// Legacy convenience fallback only. Non-EVM wallets must be passed explicitly
|
|
558
|
+
// with CAIP-2 chain context so the SDK does not route them through EVM RPC.
|
|
559
|
+
return window.ethereum || null;
|
|
560
|
+
}
|
|
466
561
|
|
|
467
562
|
async _buildPrivateGateAuth({ address, wallet, chain, signatureMethod } = {}) {
|
|
468
563
|
const providerWallet = wallet || this._getDefaultBrowserWallet();
|
|
@@ -732,10 +827,10 @@ export class NeusClient {
|
|
|
732
827
|
walletAddress = Array.isArray(accounts) && accounts.length > 0 ? accounts[0] : null;
|
|
733
828
|
}
|
|
734
829
|
}
|
|
735
|
-
} else {
|
|
736
|
-
if (typeof window === 'undefined' || !window.ethereum) {
|
|
737
|
-
throw new ConfigurationError('No EVM browser wallet detected. Provide wallet explicitly for non-EVM flows and include chain as a CAIP-2 value.');
|
|
738
|
-
}
|
|
830
|
+
} else {
|
|
831
|
+
if (typeof window === 'undefined' || !window.ethereum) {
|
|
832
|
+
throw new ConfigurationError('No EVM browser wallet detected. Provide wallet explicitly for non-EVM flows and include chain as a CAIP-2 value.');
|
|
833
|
+
}
|
|
739
834
|
await window.ethereum.request({ method: 'eth_requestAccounts' });
|
|
740
835
|
provider = window.ethereum;
|
|
741
836
|
const accounts = await provider.request({ method: 'eth_accounts' });
|
|
@@ -852,9 +947,13 @@ export class NeusClient {
|
|
|
852
947
|
verificationData = {
|
|
853
948
|
agentId: data.agentId,
|
|
854
949
|
agentWallet: data?.agentWallet || walletAddress,
|
|
950
|
+
...(data?.agentChainRef && { agentChainRef: data.agentChainRef }),
|
|
951
|
+
...(data?.agentAccountId && { agentAccountId: data.agentAccountId }),
|
|
855
952
|
...(data?.agentLabel && { agentLabel: data.agentLabel }),
|
|
856
953
|
...(data?.agentType && { agentType: data.agentType }),
|
|
954
|
+
...(data?.avatar && { avatar: data.avatar }),
|
|
857
955
|
...(data?.description && { description: data.description }),
|
|
956
|
+
...(data?.defaultRuntime && { defaultRuntime: data.defaultRuntime }),
|
|
858
957
|
...(data?.capabilities && { capabilities: data.capabilities }),
|
|
859
958
|
...(data?.instructions && { instructions: data.instructions }),
|
|
860
959
|
...(data?.skills && { skills: data.skills }),
|
|
@@ -866,7 +965,11 @@ export class NeusClient {
|
|
|
866
965
|
}
|
|
867
966
|
verificationData = {
|
|
868
967
|
controllerWallet: data?.controllerWallet || walletAddress,
|
|
968
|
+
...(data?.controllerChainRef && { controllerChainRef: data.controllerChainRef }),
|
|
869
969
|
agentWallet: data.agentWallet,
|
|
970
|
+
...(data?.agentChainRef && { agentChainRef: data.agentChainRef }),
|
|
971
|
+
...(data?.controllerAccountId && { controllerAccountId: data.controllerAccountId }),
|
|
972
|
+
...(data?.agentAccountId && { agentAccountId: data.agentAccountId }),
|
|
870
973
|
...(data?.agentId && { agentId: data.agentId }),
|
|
871
974
|
...(data?.scope && { scope: data.scope }),
|
|
872
975
|
...(data?.permissions && { permissions: data.permissions }),
|
|
@@ -875,7 +978,13 @@ export class NeusClient {
|
|
|
875
978
|
...(data?.receiptDisclosure && { receiptDisclosure: data.receiptDisclosure }),
|
|
876
979
|
...(data?.expiresAt && { expiresAt: data.expiresAt }),
|
|
877
980
|
...(data?.instructions && { instructions: data.instructions }),
|
|
878
|
-
...(data?.skills && { skills: data.skills })
|
|
981
|
+
...(data?.skills && { skills: data.skills }),
|
|
982
|
+
...(data?.model && { model: data.model }),
|
|
983
|
+
...(data?.provider && { provider: data.provider }),
|
|
984
|
+
...(data?.runtimePolicy && { runtimePolicy: data.runtimePolicy }),
|
|
985
|
+
...(data?.allowedActions && { allowedActions: data.allowedActions }),
|
|
986
|
+
...(data?.deniedActions && { deniedActions: data.deniedActions }),
|
|
987
|
+
...(data?.approvalPolicy && { approvalPolicy: data.approvalPolicy })
|
|
879
988
|
};
|
|
880
989
|
} else if (verifier === 'ai-content-moderation') {
|
|
881
990
|
if (!data?.content) {
|
|
@@ -1110,7 +1219,8 @@ export class NeusClient {
|
|
|
1110
1219
|
options: optionsPayload
|
|
1111
1220
|
};
|
|
1112
1221
|
|
|
1113
|
-
const
|
|
1222
|
+
const sponsorHeaders = await this._resolveSponsorGrantHeaders(normalizedVerifierIds);
|
|
1223
|
+
const response = await this._makeRequest('POST', '/api/v1/verification', requestData, sponsorHeaders);
|
|
1114
1224
|
|
|
1115
1225
|
if (!response.success) {
|
|
1116
1226
|
throw new ApiError(`Verification failed: ${response.error?.message || 'Unknown error'}`, response.error);
|
|
@@ -1120,11 +1230,10 @@ export class NeusClient {
|
|
|
1120
1230
|
}
|
|
1121
1231
|
|
|
1122
1232
|
async getProof(qHash) {
|
|
1123
|
-
|
|
1124
|
-
if (!resolvedQHash || typeof resolvedQHash !== 'string') {
|
|
1233
|
+
if (!qHash || typeof qHash !== 'string') {
|
|
1125
1234
|
throw new ValidationError('qHash is required');
|
|
1126
1235
|
}
|
|
1127
|
-
const response = await this._makeRequest('GET', `/api/v1/proofs/${
|
|
1236
|
+
const response = await this._makeRequest('GET', `/api/v1/proofs/${qHash}`);
|
|
1128
1237
|
|
|
1129
1238
|
if (!response.success) {
|
|
1130
1239
|
throw new ApiError(`Failed to get proof: ${response.error?.message || 'Unknown error'}`, response.error);
|
|
@@ -1134,8 +1243,7 @@ export class NeusClient {
|
|
|
1134
1243
|
}
|
|
1135
1244
|
|
|
1136
1245
|
async getPrivateProof(qHash, wallet = null) {
|
|
1137
|
-
|
|
1138
|
-
if (!resolvedQHash || typeof resolvedQHash !== 'string') {
|
|
1246
|
+
if (!qHash || typeof qHash !== 'string') {
|
|
1139
1247
|
throw new ValidationError('qHash is required');
|
|
1140
1248
|
}
|
|
1141
1249
|
|
|
@@ -1153,7 +1261,7 @@ export class NeusClient {
|
|
|
1153
1261
|
...(typeof auth.chain === 'string' && auth.chain.trim() ? { 'x-chain': auth.chain.trim() } : {}),
|
|
1154
1262
|
...(typeof auth.signatureMethod === 'string' && auth.signatureMethod.trim() ? { 'x-signature-method': auth.signatureMethod.trim() } : {})
|
|
1155
1263
|
};
|
|
1156
|
-
const response = await this._makeRequest('GET', `/api/v1/proofs/${
|
|
1264
|
+
const response = await this._makeRequest('GET', `/api/v1/proofs/${qHash}`, null, headers);
|
|
1157
1265
|
if (!response.success) {
|
|
1158
1266
|
throw new ApiError(
|
|
1159
1267
|
`Failed to access private proof: ${response.error?.message || 'Unauthorized'}`,
|
|
@@ -1177,7 +1285,7 @@ export class NeusClient {
|
|
|
1177
1285
|
const message = constructVerificationMessage({
|
|
1178
1286
|
walletAddress,
|
|
1179
1287
|
signedTimestamp,
|
|
1180
|
-
data: { action: 'access_private_proof', qHash:
|
|
1288
|
+
data: { action: 'access_private_proof', qHash: qHash },
|
|
1181
1289
|
verifierIds: ['ownership-basic'],
|
|
1182
1290
|
...(signerIsEvm ? { chainId: this._getHubChainId() } : { chain })
|
|
1183
1291
|
});
|
|
@@ -1197,7 +1305,7 @@ export class NeusClient {
|
|
|
1197
1305
|
throw new ValidationError(`Failed to sign message: ${error.message}`);
|
|
1198
1306
|
}
|
|
1199
1307
|
|
|
1200
|
-
const response = await this._makeRequest('GET', `/api/v1/proofs/${
|
|
1308
|
+
const response = await this._makeRequest('GET', `/api/v1/proofs/${qHash}`, null, {
|
|
1201
1309
|
'x-wallet-address': walletAddress,
|
|
1202
1310
|
'x-signature': signature,
|
|
1203
1311
|
'x-signed-timestamp': signedTimestamp.toString(),
|
|
@@ -1247,14 +1355,13 @@ export class NeusClient {
|
|
|
1247
1355
|
}
|
|
1248
1356
|
|
|
1249
1357
|
async pollProofStatus(qHash, options = {}) {
|
|
1250
|
-
const resolvedQHash = qHash; // Legacy input compatibility only. Do not expose or store proofId.
|
|
1251
1358
|
const {
|
|
1252
1359
|
interval = 5000,
|
|
1253
1360
|
timeout = 120000,
|
|
1254
1361
|
onProgress
|
|
1255
1362
|
} = options;
|
|
1256
1363
|
|
|
1257
|
-
if (!
|
|
1364
|
+
if (!qHash || typeof qHash !== 'string') {
|
|
1258
1365
|
throw new ValidationError('qHash is required');
|
|
1259
1366
|
}
|
|
1260
1367
|
|
|
@@ -1263,7 +1370,7 @@ export class NeusClient {
|
|
|
1263
1370
|
|
|
1264
1371
|
while (Date.now() - startTime < timeout) {
|
|
1265
1372
|
try {
|
|
1266
|
-
const status = await this.getProof(
|
|
1373
|
+
const status = await this.getProof(qHash);
|
|
1267
1374
|
consecutiveRateLimits = 0;
|
|
1268
1375
|
|
|
1269
1376
|
if (onProgress && typeof onProgress === 'function') {
|
|
@@ -1316,8 +1423,7 @@ export class NeusClient {
|
|
|
1316
1423
|
}
|
|
1317
1424
|
|
|
1318
1425
|
async revokeOwnProof(qHash, wallet) {
|
|
1319
|
-
|
|
1320
|
-
if (!resolvedQHash || typeof resolvedQHash !== 'string') {
|
|
1426
|
+
if (!qHash || typeof qHash !== 'string') {
|
|
1321
1427
|
throw new ValidationError('qHash is required');
|
|
1322
1428
|
}
|
|
1323
1429
|
const providerWallet = wallet || this._getDefaultBrowserWallet();
|
|
@@ -1333,7 +1439,7 @@ export class NeusClient {
|
|
|
1333
1439
|
const message = constructVerificationMessage({
|
|
1334
1440
|
walletAddress: address,
|
|
1335
1441
|
signedTimestamp,
|
|
1336
|
-
data: { action: 'revoke_proof', qHash:
|
|
1442
|
+
data: { action: 'revoke_proof', qHash: qHash },
|
|
1337
1443
|
verifierIds: ['ownership-basic'],
|
|
1338
1444
|
...(signerIsEvm ? { chainId: this._getHubChainId() } : { chain })
|
|
1339
1445
|
});
|
|
@@ -1353,7 +1459,7 @@ export class NeusClient {
|
|
|
1353
1459
|
throw new ValidationError(`Failed to sign revocation: ${error.message}`);
|
|
1354
1460
|
}
|
|
1355
1461
|
|
|
1356
|
-
const res = await this._makeRequest('POST', `/api/v1/proofs/revoke-self/${
|
|
1462
|
+
const res = await this._makeRequest('POST', `/api/v1/proofs/revoke-self/${qHash}`, {
|
|
1357
1463
|
walletAddress: address,
|
|
1358
1464
|
signature,
|
|
1359
1465
|
signedTimestamp,
|
|
@@ -1586,7 +1692,23 @@ export class NeusClient {
|
|
|
1586
1692
|
}
|
|
1587
1693
|
}
|
|
1588
1694
|
|
|
1589
|
-
|
|
1695
|
+
let mergedHeaders = headersOverride;
|
|
1696
|
+
if (!mergedHeaders) {
|
|
1697
|
+
try {
|
|
1698
|
+
const sponsorHeaders = await this._resolveSponsorGrantHeaders(
|
|
1699
|
+
Array.isArray(params.verifierIds)
|
|
1700
|
+
? params.verifierIds
|
|
1701
|
+
: (params.verifierIds ? [params.verifierIds] : [])
|
|
1702
|
+
);
|
|
1703
|
+
if (sponsorHeaders && Object.keys(sponsorHeaders).length > 0) {
|
|
1704
|
+
mergedHeaders = sponsorHeaders;
|
|
1705
|
+
}
|
|
1706
|
+
} catch (error) {
|
|
1707
|
+
this._log('Sponsor grant unavailable for gateCheck (continuing without)', error?.message || String(error));
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
const response = await this._makeRequest('GET', `/api/v1/proofs/check?${qs.toString()}`, null, mergedHeaders);
|
|
1590
1712
|
if (!response.success) {
|
|
1591
1713
|
throw new ApiError(`Gate check failed: ${response.error?.message || 'Unknown error'}`, response.error);
|
|
1592
1714
|
}
|
|
@@ -1848,9 +1970,6 @@ export class NeusClient {
|
|
|
1848
1970
|
const qHash = response?.data?.qHash ||
|
|
1849
1971
|
response?.qHash ||
|
|
1850
1972
|
response?.data?.resource?.qHash ||
|
|
1851
|
-
response?.data?.proofId || // Legacy input compatibility only. Do not expose or store proofId.
|
|
1852
|
-
response?.proofId || // Legacy input compatibility only. Do not expose or store proofId.
|
|
1853
|
-
response?.data?.resource?.proofId || // Legacy input compatibility only. Do not expose or store proofId.
|
|
1854
1973
|
response?.data?.id;
|
|
1855
1974
|
|
|
1856
1975
|
const status = response?.data?.status ||
|
package/errors.js
CHANGED
|
@@ -1,189 +1,154 @@
|
|
|
1
|
-
export class SDKError extends Error {
|
|
2
|
-
constructor(message, code = 'SDK_ERROR', details = {}) {
|
|
3
|
-
super(message);
|
|
4
|
-
this.name = 'SDKError';
|
|
5
|
-
this.code = code;
|
|
6
|
-
this.details = details;
|
|
7
|
-
this.timestamp = Date.now();
|
|
8
|
-
|
|
9
|
-
if (Error.captureStackTrace) {
|
|
10
|
-
Error.captureStackTrace(this, SDKError);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
toJSON() {
|
|
15
|
-
return {
|
|
16
|
-
name: this.name,
|
|
17
|
-
message: this.message,
|
|
18
|
-
code: this.code,
|
|
19
|
-
details: this.details,
|
|
20
|
-
timestamp: this.timestamp
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export class ApiError extends SDKError {
|
|
26
|
-
constructor(message, statusCode = 500, code = 'API_ERROR', response = null) {
|
|
27
|
-
super(message, code);
|
|
28
|
-
this.name = 'ApiError';
|
|
29
|
-
this.statusCode = statusCode;
|
|
30
|
-
this.response = response;
|
|
31
|
-
|
|
32
|
-
this.isClientError = statusCode >= 400 && statusCode < 500;
|
|
33
|
-
this.isServerError = statusCode >= 500;
|
|
34
|
-
this.isRetryable = this.isServerError || statusCode === 429; // Server errors or rate limit
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
static fromResponse(response, responseData) {
|
|
38
|
-
const statusCode = response.status;
|
|
39
|
-
const message = responseData?.error?.message ||
|
|
40
|
-
responseData?.message ||
|
|
41
|
-
`API request failed with status ${statusCode}`;
|
|
42
|
-
const code = responseData?.error?.code || 'API_ERROR';
|
|
43
|
-
|
|
44
|
-
return new ApiError(message, statusCode, code, responseData);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
toJSON() {
|
|
48
|
-
return {
|
|
49
|
-
...super.toJSON(),
|
|
50
|
-
statusCode: this.statusCode,
|
|
51
|
-
isClientError: this.isClientError,
|
|
52
|
-
isServerError: this.isServerError,
|
|
53
|
-
isRetryable: this.isRetryable
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export class ValidationError extends SDKError {
|
|
59
|
-
constructor(message, field = null, value = null) {
|
|
60
|
-
super(message, 'VALIDATION_ERROR');
|
|
61
|
-
this.name = 'ValidationError';
|
|
62
|
-
this.field = field;
|
|
63
|
-
this.value = value;
|
|
64
|
-
this.isRetryable = false; // Validation errors are not retryable
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
toJSON() {
|
|
68
|
-
return {
|
|
69
|
-
...super.toJSON(),
|
|
70
|
-
field: this.field,
|
|
71
|
-
value: this.value,
|
|
72
|
-
isRetryable: this.isRetryable
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export class NetworkError extends SDKError {
|
|
78
|
-
constructor(message, code = 'NETWORK_ERROR', originalError = null) {
|
|
79
|
-
super(message, code);
|
|
80
|
-
this.name = 'NetworkError';
|
|
81
|
-
this.originalError = originalError;
|
|
82
|
-
this.isRetryable = true; // Network errors are retryable
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
static isNetworkError(error) {
|
|
86
|
-
return error instanceof NetworkError ||
|
|
87
|
-
error.name === 'TypeError' && error.message.includes('fetch') ||
|
|
88
|
-
error.name === 'AbortError' ||
|
|
89
|
-
error.code === 'ENOTFOUND' ||
|
|
90
|
-
error.code === 'ECONNREFUSED' ||
|
|
91
|
-
error.code === 'ETIMEDOUT';
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
toJSON() {
|
|
95
|
-
return {
|
|
96
|
-
...super.toJSON(),
|
|
97
|
-
isRetryable: this.isRetryable,
|
|
98
|
-
originalError: this.originalError ? {
|
|
99
|
-
name: this.originalError.name,
|
|
100
|
-
message: this.originalError.message,
|
|
101
|
-
code: this.originalError.code
|
|
102
|
-
} : null
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export class ConfigurationError extends SDKError {
|
|
108
|
-
constructor(message, configKey = null) {
|
|
109
|
-
super(message, 'CONFIGURATION_ERROR');
|
|
110
|
-
this.name = 'ConfigurationError';
|
|
111
|
-
this.configKey = configKey;
|
|
112
|
-
this.isRetryable = false; // Config errors require user intervention
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
toJSON() {
|
|
116
|
-
return {
|
|
117
|
-
...super.toJSON(),
|
|
118
|
-
configKey: this.configKey,
|
|
119
|
-
isRetryable: this.isRetryable
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export class VerificationError extends SDKError {
|
|
125
|
-
constructor(message, verifierId = null, code = 'VERIFICATION_ERROR') {
|
|
126
|
-
super(message, code);
|
|
127
|
-
this.name = 'VerificationError';
|
|
128
|
-
this.verifierId = verifierId;
|
|
129
|
-
this.isRetryable = true; // Some verification errors might be retryable
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
toJSON() {
|
|
133
|
-
return {
|
|
134
|
-
...super.toJSON(),
|
|
135
|
-
verifierId: this.verifierId,
|
|
136
|
-
isRetryable: this.isRetryable
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export class AuthenticationError extends SDKError {
|
|
142
|
-
constructor(message, code = 'AUTHENTICATION_ERROR') {
|
|
143
|
-
super(message, code);
|
|
144
|
-
this.name = 'AuthenticationError';
|
|
145
|
-
this.isRetryable = false; // Auth errors require user intervention
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
toJSON() {
|
|
149
|
-
return {
|
|
150
|
-
...super.toJSON(),
|
|
151
|
-
isRetryable: this.isRetryable
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export function createErrorFromGeneric(error, context = {}) {
|
|
157
|
-
if (error instanceof SDKError) {
|
|
158
|
-
return error;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (NetworkError.isNetworkError(error)) {
|
|
162
|
-
return new NetworkError(
|
|
163
|
-
error.message || 'Network error occurred',
|
|
164
|
-
error.code || 'NETWORK_ERROR',
|
|
165
|
-
error
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (error.name === 'AbortError' || error.message.includes('timeout')) {
|
|
170
|
-
return new NetworkError('Request timeout', 'TIMEOUT', error);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return new SDKError(
|
|
174
|
-
error.message || 'Unknown error occurred',
|
|
175
|
-
error.code || 'UNKNOWN_ERROR',
|
|
176
|
-
{ originalError: error, context }
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
export default {
|
|
181
|
-
SDKError,
|
|
182
|
-
ApiError,
|
|
183
|
-
ValidationError,
|
|
184
|
-
NetworkError,
|
|
185
|
-
ConfigurationError,
|
|
186
|
-
VerificationError,
|
|
187
|
-
AuthenticationError,
|
|
188
|
-
createErrorFromGeneric
|
|
189
|
-
};
|
|
1
|
+
export class SDKError extends Error {
|
|
2
|
+
constructor(message, code = 'SDK_ERROR', details = {}) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = 'SDKError';
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.details = details;
|
|
7
|
+
this.timestamp = Date.now();
|
|
8
|
+
|
|
9
|
+
if (Error.captureStackTrace) {
|
|
10
|
+
Error.captureStackTrace(this, SDKError);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
toJSON() {
|
|
15
|
+
return {
|
|
16
|
+
name: this.name,
|
|
17
|
+
message: this.message,
|
|
18
|
+
code: this.code,
|
|
19
|
+
details: this.details,
|
|
20
|
+
timestamp: this.timestamp
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class ApiError extends SDKError {
|
|
26
|
+
constructor(message, statusCode = 500, code = 'API_ERROR', response = null) {
|
|
27
|
+
super(message, code);
|
|
28
|
+
this.name = 'ApiError';
|
|
29
|
+
this.statusCode = statusCode;
|
|
30
|
+
this.response = response;
|
|
31
|
+
|
|
32
|
+
this.isClientError = statusCode >= 400 && statusCode < 500;
|
|
33
|
+
this.isServerError = statusCode >= 500;
|
|
34
|
+
this.isRetryable = this.isServerError || statusCode === 429; // Server errors or rate limit
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static fromResponse(response, responseData) {
|
|
38
|
+
const statusCode = response.status;
|
|
39
|
+
const message = responseData?.error?.message ||
|
|
40
|
+
responseData?.message ||
|
|
41
|
+
`API request failed with status ${statusCode}`;
|
|
42
|
+
const code = responseData?.error?.code || 'API_ERROR';
|
|
43
|
+
|
|
44
|
+
return new ApiError(message, statusCode, code, responseData);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
toJSON() {
|
|
48
|
+
return {
|
|
49
|
+
...super.toJSON(),
|
|
50
|
+
statusCode: this.statusCode,
|
|
51
|
+
isClientError: this.isClientError,
|
|
52
|
+
isServerError: this.isServerError,
|
|
53
|
+
isRetryable: this.isRetryable
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class ValidationError extends SDKError {
|
|
59
|
+
constructor(message, field = null, value = null) {
|
|
60
|
+
super(message, 'VALIDATION_ERROR');
|
|
61
|
+
this.name = 'ValidationError';
|
|
62
|
+
this.field = field;
|
|
63
|
+
this.value = value;
|
|
64
|
+
this.isRetryable = false; // Validation errors are not retryable
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
toJSON() {
|
|
68
|
+
return {
|
|
69
|
+
...super.toJSON(),
|
|
70
|
+
field: this.field,
|
|
71
|
+
value: this.value,
|
|
72
|
+
isRetryable: this.isRetryable
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export class NetworkError extends SDKError {
|
|
78
|
+
constructor(message, code = 'NETWORK_ERROR', originalError = null) {
|
|
79
|
+
super(message, code);
|
|
80
|
+
this.name = 'NetworkError';
|
|
81
|
+
this.originalError = originalError;
|
|
82
|
+
this.isRetryable = true; // Network errors are retryable
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static isNetworkError(error) {
|
|
86
|
+
return error instanceof NetworkError ||
|
|
87
|
+
error.name === 'TypeError' && error.message.includes('fetch') ||
|
|
88
|
+
error.name === 'AbortError' ||
|
|
89
|
+
error.code === 'ENOTFOUND' ||
|
|
90
|
+
error.code === 'ECONNREFUSED' ||
|
|
91
|
+
error.code === 'ETIMEDOUT';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
toJSON() {
|
|
95
|
+
return {
|
|
96
|
+
...super.toJSON(),
|
|
97
|
+
isRetryable: this.isRetryable,
|
|
98
|
+
originalError: this.originalError ? {
|
|
99
|
+
name: this.originalError.name,
|
|
100
|
+
message: this.originalError.message,
|
|
101
|
+
code: this.originalError.code
|
|
102
|
+
} : null
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export class ConfigurationError extends SDKError {
|
|
108
|
+
constructor(message, configKey = null) {
|
|
109
|
+
super(message, 'CONFIGURATION_ERROR');
|
|
110
|
+
this.name = 'ConfigurationError';
|
|
111
|
+
this.configKey = configKey;
|
|
112
|
+
this.isRetryable = false; // Config errors require user intervention
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
toJSON() {
|
|
116
|
+
return {
|
|
117
|
+
...super.toJSON(),
|
|
118
|
+
configKey: this.configKey,
|
|
119
|
+
isRetryable: this.isRetryable
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export class VerificationError extends SDKError {
|
|
125
|
+
constructor(message, verifierId = null, code = 'VERIFICATION_ERROR') {
|
|
126
|
+
super(message, code);
|
|
127
|
+
this.name = 'VerificationError';
|
|
128
|
+
this.verifierId = verifierId;
|
|
129
|
+
this.isRetryable = true; // Some verification errors might be retryable
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
toJSON() {
|
|
133
|
+
return {
|
|
134
|
+
...super.toJSON(),
|
|
135
|
+
verifierId: this.verifierId,
|
|
136
|
+
isRetryable: this.isRetryable
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export class AuthenticationError extends SDKError {
|
|
142
|
+
constructor(message, code = 'AUTHENTICATION_ERROR') {
|
|
143
|
+
super(message, code);
|
|
144
|
+
this.name = 'AuthenticationError';
|
|
145
|
+
this.isRetryable = false; // Auth errors require user intervention
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
toJSON() {
|
|
149
|
+
return {
|
|
150
|
+
...super.toJSON(),
|
|
151
|
+
isRetryable: this.isRetryable
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|