@neus/sdk 1.1.0 → 1.1.2

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/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,
@@ -396,6 +397,77 @@ export class NeusClient {
396
397
  } catch {
397
398
  void 0;
398
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 };
399
471
  }
400
472
 
401
473
  _getHubChainId() {
@@ -980,23 +1052,22 @@ export class NeusClient {
980
1052
  }
981
1053
  };
982
1054
 
983
- const isFarcasterWallet = (() => {
1055
+ const isBaseMiniAppWallet = (() => {
984
1056
  if (typeof window === 'undefined') return false;
985
1057
  try {
986
1058
  const w = window;
987
- const fc = w.farcaster;
988
- if (!fc || !fc.context) return false;
989
- const fcProvider = fc.provider || fc.walletProvider || (fc.context && fc.context.walletProvider);
990
- if (fcProvider === provider) return true;
991
- if (w.mini && w.mini.wallet === provider && fc && fc.context) return true;
992
- if (w.ethereum === provider && fc && fc.context) return true;
1059
+ const mini = w.mini;
1060
+ if (!mini) return false;
1061
+ const miniProvider = mini.wallet || mini.provider;
1062
+ if (miniProvider === provider) return true;
1063
+ if (w.ethereum === provider && mini) return true;
993
1064
  } catch {
994
1065
  void 0;
995
1066
  }
996
1067
  return false;
997
1068
  })();
998
1069
 
999
- if (isFarcasterWallet) {
1070
+ if (isBaseMiniAppWallet) {
1000
1071
  try {
1001
1072
  const hexMsg = toHexUtf8(message);
1002
1073
  signature = await provider.request({ method: 'personal_sign', params: [hexMsg, walletAddress] });
@@ -1147,7 +1218,8 @@ export class NeusClient {
1147
1218
  options: optionsPayload
1148
1219
  };
1149
1220
 
1150
- const response = await this._makeRequest('POST', '/api/v1/verification', requestData);
1221
+ const sponsorHeaders = await this._resolveSponsorGrantHeaders(normalizedVerifierIds);
1222
+ const response = await this._makeRequest('POST', '/api/v1/verification', requestData, sponsorHeaders);
1151
1223
 
1152
1224
  if (!response.success) {
1153
1225
  throw new ApiError(`Verification failed: ${response.error?.message || 'Unknown error'}`, response.error);
@@ -1409,7 +1481,9 @@ export class NeusClient {
1409
1481
 
1410
1482
  const qs = [];
1411
1483
  if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1412
- if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1484
+ const cursorRaw = options.cursor !== null && options.cursor !== undefined ? String(options.cursor).trim() : '';
1485
+ if (cursorRaw) qs.push(`cursor=${encodeURIComponent(cursorRaw)}`);
1486
+ else if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1413
1487
  if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
1414
1488
 
1415
1489
  const query = qs.length ? `?${qs.join('&')}` : '';
@@ -1428,7 +1502,11 @@ export class NeusClient {
1428
1502
  proofs: Array.isArray(proofs) ? proofs : [],
1429
1503
  totalCount: response.data?.totalCount ?? proofs.length,
1430
1504
  hasMore: Boolean(response.data?.hasMore),
1431
- nextOffset: response.data?.nextOffset ?? null
1505
+ nextOffset: response.data?.nextOffset ?? null,
1506
+ nextCursor:
1507
+ typeof response.data?.nextCursor === 'string' && response.data.nextCursor.trim()
1508
+ ? response.data.nextCursor.trim()
1509
+ : null
1432
1510
  };
1433
1511
  }
1434
1512
 
@@ -1493,7 +1571,9 @@ export class NeusClient {
1493
1571
 
1494
1572
  const qs = [];
1495
1573
  if (options.limit) qs.push(`limit=${encodeURIComponent(String(options.limit))}`);
1496
- if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1574
+ const cursorRaw = options.cursor !== null && options.cursor !== undefined ? String(options.cursor).trim() : '';
1575
+ if (cursorRaw) qs.push(`cursor=${encodeURIComponent(cursorRaw)}`);
1576
+ else if (options.offset) qs.push(`offset=${encodeURIComponent(String(options.offset))}`);
1497
1577
  if (options.qHash) qs.push(`qHash=${encodeURIComponent(options.qHash.toLowerCase())}`);
1498
1578
  const query = qs.length ? `?${qs.join('&')}` : '';
1499
1579
 
@@ -1514,7 +1594,11 @@ export class NeusClient {
1514
1594
  proofs: Array.isArray(proofs) ? proofs : [],
1515
1595
  totalCount: response.data?.totalCount ?? proofs.length,
1516
1596
  hasMore: Boolean(response.data?.hasMore),
1517
- nextOffset: response.data?.nextOffset ?? null
1597
+ nextOffset: response.data?.nextOffset ?? null,
1598
+ nextCursor:
1599
+ typeof response.data?.nextCursor === 'string' && response.data.nextCursor.trim()
1600
+ ? response.data.nextCursor.trim()
1601
+ : null
1518
1602
  };
1519
1603
  }
1520
1604
 
@@ -1524,6 +1608,9 @@ export class NeusClient {
1524
1608
  throw new ValidationError('Valid address is required');
1525
1609
  }
1526
1610
 
1611
+ const gateIdParam = typeof params.gateId === 'string' ? params.gateId.trim() : '';
1612
+ const verifierIds = gateIdParam ? undefined : params.verifierIds;
1613
+
1527
1614
  const qs = new URLSearchParams();
1528
1615
  qs.set('address', address);
1529
1616
 
@@ -1549,7 +1636,8 @@ export class NeusClient {
1549
1636
  setIfPresent(key, value);
1550
1637
  };
1551
1638
 
1552
- setCsvIfPresent('verifierIds', params.verifierIds);
1639
+ setIfPresent('gateId', gateIdParam);
1640
+ setCsvIfPresent('verifierIds', verifierIds);
1553
1641
  setBoolIfPresent('requireAll', params.requireAll);
1554
1642
  setIfPresent('minCount', params.minCount);
1555
1643
  setIfPresent('sinceDays', params.sinceDays);
@@ -1619,7 +1707,23 @@ export class NeusClient {
1619
1707
  }
1620
1708
  }
1621
1709
 
1622
- const response = await this._makeRequest('GET', `/api/v1/proofs/check?${qs.toString()}`, null, headersOverride);
1710
+ let mergedHeaders = headersOverride;
1711
+ if (!mergedHeaders && !gateIdParam) {
1712
+ try {
1713
+ const sponsorHeaders = await this._resolveSponsorGrantHeaders(
1714
+ Array.isArray(verifierIds)
1715
+ ? verifierIds
1716
+ : (verifierIds ? [verifierIds] : [])
1717
+ );
1718
+ if (sponsorHeaders && Object.keys(sponsorHeaders).length > 0) {
1719
+ mergedHeaders = sponsorHeaders;
1720
+ }
1721
+ } catch (error) {
1722
+ this._log('Sponsor grant unavailable for gateCheck (continuing without)', error?.message || String(error));
1723
+ }
1724
+ }
1725
+
1726
+ const response = await this._makeRequest('GET', `/api/v1/proofs/check?${qs.toString()}`, null, mergedHeaders);
1623
1727
  if (!response.success) {
1624
1728
  throw new ApiError(`Gate check failed: ${response.error?.message || 'Unknown error'}`, response.error);
1625
1729
  }
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
+ }
package/gates.js CHANGED
@@ -51,23 +51,3 @@ export function combineGates(...gates) {
51
51
 
52
52
  return combined;
53
53
  }
54
-
55
- export default {
56
- HOUR,
57
- DAY,
58
- WEEK,
59
- MONTH,
60
- YEAR,
61
- GATE_NFT_HOLDER,
62
- GATE_TOKEN_HOLDER,
63
- GATE_CONTRACT_ADMIN,
64
- GATE_DOMAIN_OWNER,
65
- GATE_LINKED_WALLETS,
66
- GATE_AGENT_IDENTITY,
67
- GATE_AGENT_DELEGATION,
68
- GATE_CONTENT_MODERATION,
69
- GATE_WALLET_RISK,
70
- GATE_PSEUDONYM,
71
- createGate,
72
- combineGates
73
- };
package/index.js CHANGED
@@ -55,6 +55,8 @@ export {
55
55
  combineGates
56
56
  } from './gates.js';
57
57
 
58
+ export { fetchSponsorGrant } from './sponsor.js';
59
+
58
60
  export {
59
61
  SDKError,
60
62
  ApiError,