@sudobility/indexer_client 0.0.118 → 0.0.120
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 +56 -554
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -1,594 +1,96 @@
|
|
|
1
1
|
# @sudobility/indexer_client
|
|
2
2
|
|
|
3
|
-
TypeScript client library for the blockchain
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- ✅ **Complete Type Safety** - Full TypeScript support with `@sudobility/types`
|
|
8
|
-
- ✅ **React Integration** - Built-in hooks using `@tanstack/react-query`
|
|
9
|
-
- ✅ **Multi-Chain Support** - EVM and Solana blockchains
|
|
10
|
-
- ✅ **Authentication** - SIWE/SIWS signature verification
|
|
11
|
-
- ✅ **Points System** - Track and display user points
|
|
12
|
-
- ✅ **Referral System** - Generate and track referral codes
|
|
13
|
-
- ✅ **Name Service** - ENS and SNS resolution
|
|
14
|
-
- ✅ **Delegation** - Wallet delegation management
|
|
15
|
-
- ✅ **Development Mode** - Mock data for testing
|
|
3
|
+
TypeScript client library for the 0xMail blockchain indexer REST and GraphQL APIs. Provides an `IndexerClient` class, TanStack React Query hooks, GraphQL/admin/webhook helpers, and a business service layer. Works cross-platform on React and React Native via an injected `NetworkClient` interface.
|
|
16
4
|
|
|
17
5
|
## Installation
|
|
18
6
|
|
|
19
7
|
```bash
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### Peer Dependencies
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npm install react @tanstack/react-query axios @sudobility/di@^1.4.7 @sudobility/types@^1.8.29
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
**Current Versions:**
|
|
30
|
-
- `@sudobility/di` v1.4.7
|
|
31
|
-
- `@sudobility/types` v1.8.29
|
|
32
|
-
|
|
33
|
-
## Quick Start
|
|
34
|
-
|
|
35
|
-
### 1. Setup React Query
|
|
36
|
-
|
|
37
|
-
```typescript
|
|
38
|
-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
39
|
-
|
|
40
|
-
const queryClient = new QueryClient({
|
|
41
|
-
defaultOptions: {
|
|
42
|
-
queries: {
|
|
43
|
-
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
function App() {
|
|
49
|
-
return (
|
|
50
|
-
<QueryClientProvider client={queryClient}>
|
|
51
|
-
{/* Your app */}
|
|
52
|
-
</QueryClientProvider>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
8
|
+
bun add @sudobility/indexer_client
|
|
55
9
|
```
|
|
56
10
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
import { useIndexerPoints } from '@sudobility/indexer_client';
|
|
61
|
-
|
|
62
|
-
function PointsDisplay({ wallet, signature, message }) {
|
|
63
|
-
const { data, isLoading } = useIndexerPoints(
|
|
64
|
-
'https://indexer.example.com',
|
|
65
|
-
false, // dev mode
|
|
66
|
-
wallet,
|
|
67
|
-
signature,
|
|
68
|
-
message
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
if (isLoading) return <div>Loading...</div>;
|
|
72
|
-
if (!data?.success) return <div>Error</div>;
|
|
73
|
-
|
|
74
|
-
return <div>Points: {data.data.pointsEarned}</div>;
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## API Coverage
|
|
79
|
-
|
|
80
|
-
| Feature | Status | Endpoints |
|
|
81
|
-
|---------|--------|-----------|
|
|
82
|
-
| Mail & User Management | ✅ 71% | 12/17 implemented |
|
|
83
|
-
| Points System | ✅ 100% | 3/3 implemented |
|
|
84
|
-
| Referral System | ✅ 100% | Fully implemented |
|
|
85
|
-
| OAuth 2.0 | ❌ 0% | Planned for v1.0 |
|
|
86
|
-
| KYC Verification | ❌ 0% | Optional feature |
|
|
87
|
-
| Solana Admin | ❌ 0% | Admin tools |
|
|
11
|
+
Peer dependencies: `react` (>=18), `@tanstack/react-query` (>=5), `@sudobility/di`, `@sudobility/types`, `@sudobility/mail_box_types`, `@sudobility/configs`.
|
|
88
12
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
## Documentation
|
|
92
|
-
|
|
93
|
-
- **[docs/API.md](docs/API.md)** - Complete API endpoint documentation
|
|
94
|
-
- **[docs/EXAMPLES.md](docs/EXAMPLES.md)** - Code examples for all features
|
|
95
|
-
- **[docs/HOOKS_DOCUMENTATION.md](docs/HOOKS_DOCUMENTATION.md)** - Comprehensive hook documentation
|
|
96
|
-
- **[docs/AI_DEVELOPMENT_GUIDE.md](docs/AI_DEVELOPMENT_GUIDE.md)** - Guide for AI-assisted development
|
|
97
|
-
- **[docs/CONTRIBUTING.md](docs/CONTRIBUTING.md)** - Development and contribution guidelines
|
|
98
|
-
- **[docs/COVERAGE.md](docs/COVERAGE.md)** - API implementation status
|
|
99
|
-
|
|
100
|
-
## Core Components
|
|
101
|
-
|
|
102
|
-
### IndexerClient
|
|
103
|
-
|
|
104
|
-
Low-level HTTP client for direct API access:
|
|
13
|
+
## Usage
|
|
105
14
|
|
|
106
15
|
```typescript
|
|
107
16
|
import { IndexerClient } from '@sudobility/indexer_client';
|
|
108
17
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
// Get signing message
|
|
115
|
-
const msgResult = await client.getMessage(
|
|
116
|
-
'0x742d35Cc...',
|
|
117
|
-
1, // chainId
|
|
118
|
-
'example.com',
|
|
119
|
-
'https://example.com'
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
// Get points balance (requires signature)
|
|
123
|
-
const points = await client.getPointsBalance(wallet, signature, message);
|
|
18
|
+
// Core client (uses injected NetworkClient for cross-platform HTTP)
|
|
19
|
+
const client = new IndexerClient(endpointUrl, networkClient, dev);
|
|
20
|
+
const accounts = await client.getWalletAccounts(walletAddress, auth);
|
|
21
|
+
const points = await client.getPointsBalance(walletAddress, auth);
|
|
124
22
|
```
|
|
125
23
|
|
|
126
24
|
### React Hooks
|
|
127
25
|
|
|
128
|
-
High-level hooks with automatic caching and refetching:
|
|
129
|
-
|
|
130
|
-
#### useIndexerMail
|
|
131
|
-
```typescript
|
|
132
|
-
import { useIndexerMail } from '@sudobility/indexer_client';
|
|
133
|
-
|
|
134
|
-
const { data, isLoading, error, refetch } = useIndexerMail(
|
|
135
|
-
endpointUrl,
|
|
136
|
-
dev,
|
|
137
|
-
walletAddress,
|
|
138
|
-
signature,
|
|
139
|
-
message
|
|
140
|
-
);
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
#### useIndexerPoints
|
|
144
|
-
```typescript
|
|
145
|
-
import { useIndexerPoints } from '@sudobility/indexer_client';
|
|
146
|
-
|
|
147
|
-
const { data, isLoading } = useIndexerPoints(
|
|
148
|
-
endpointUrl,
|
|
149
|
-
dev,
|
|
150
|
-
walletAddress,
|
|
151
|
-
signature,
|
|
152
|
-
message
|
|
153
|
-
);
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
#### useIndexerReferralCode
|
|
157
|
-
```typescript
|
|
158
|
-
import { useIndexerReferralCode } from '@sudobility/indexer_client';
|
|
159
|
-
|
|
160
|
-
const { data, isLoading } = useIndexerReferralCode(
|
|
161
|
-
endpointUrl,
|
|
162
|
-
dev,
|
|
163
|
-
walletAddress,
|
|
164
|
-
signature,
|
|
165
|
-
message
|
|
166
|
-
);
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
#### useIndexerReferralStats
|
|
170
|
-
```typescript
|
|
171
|
-
import { useIndexerReferralStats } from '@sudobility/indexer_client';
|
|
172
|
-
|
|
173
|
-
const { data, isLoading } = useIndexerReferralStats(
|
|
174
|
-
endpointUrl,
|
|
175
|
-
dev,
|
|
176
|
-
referralCode
|
|
177
|
-
);
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
#### useWalletNames / useResolveNameToAddress
|
|
181
|
-
```typescript
|
|
182
|
-
import { useWalletNames, useResolveNameToAddress } from '@sudobility/indexer_client';
|
|
183
|
-
|
|
184
|
-
// Get all names for a wallet
|
|
185
|
-
const { data: names } = useWalletNames(
|
|
186
|
-
endpointUrl,
|
|
187
|
-
dev,
|
|
188
|
-
walletAddress,
|
|
189
|
-
signature,
|
|
190
|
-
message
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
// Resolve name to address
|
|
194
|
-
const { data: resolved } = useResolveNameToAddress(
|
|
195
|
-
endpointUrl,
|
|
196
|
-
dev,
|
|
197
|
-
'vitalik.eth'
|
|
198
|
-
);
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### Business Services
|
|
202
|
-
|
|
203
|
-
#### IndexerService
|
|
204
|
-
Caching wrapper for public endpoints:
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
import { IndexerService } from '@sudobility/indexer_client';
|
|
208
|
-
|
|
209
|
-
const config = {
|
|
210
|
-
indexerBackendUrl: 'https://indexer.example.com'
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
const service = IndexerService.getInstance(config);
|
|
214
|
-
|
|
215
|
-
// Get leaderboard (cached for 5 minutes)
|
|
216
|
-
const leaderboard = await service.getLeaderboard(10);
|
|
217
|
-
|
|
218
|
-
// Get public stats
|
|
219
|
-
const stats = await service.getPublicStats();
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Factory Helpers
|
|
223
|
-
|
|
224
|
-
Create helper instances with automatic client injection:
|
|
225
|
-
|
|
226
26
|
```typescript
|
|
227
27
|
import {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
28
|
+
useIndexerGetWalletAccounts,
|
|
29
|
+
useIndexerPointsInfo,
|
|
30
|
+
useIndexerPointsLeaderboard,
|
|
31
|
+
useIndexerGetDelegatedTo,
|
|
32
|
+
useWalletNames,
|
|
33
|
+
useResolveNameToAddress,
|
|
34
|
+
useIndexerMailTemplates,
|
|
35
|
+
useIndexerMailWebhooks,
|
|
36
|
+
useIndexerReferralCode,
|
|
232
37
|
} from '@sudobility/indexer_client';
|
|
233
38
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
// Create individual helpers
|
|
239
|
-
const admin = createIndexerAdmin(config);
|
|
240
|
-
const graphql = createIndexerGraphQL(config);
|
|
241
|
-
const webhook = createIndexerWebhook(config);
|
|
242
|
-
|
|
243
|
-
// Or create all at once
|
|
244
|
-
const { admin, graphql, webhook } = createIndexerHelpers(config);
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
## Authentication
|
|
248
|
-
|
|
249
|
-
All protected endpoints require signature authentication:
|
|
250
|
-
|
|
251
|
-
### 1. Generate Message
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
const msgResult = await client.getMessage(
|
|
255
|
-
walletAddress,
|
|
256
|
-
chainId,
|
|
257
|
-
'domain.com',
|
|
258
|
-
'https://domain.com'
|
|
259
|
-
);
|
|
260
|
-
const message = msgResult.data.message;
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### 2. Sign Message
|
|
264
|
-
|
|
265
|
-
**EVM (ethers.js):**
|
|
266
|
-
```typescript
|
|
267
|
-
import { ethers } from 'ethers';
|
|
268
|
-
|
|
269
|
-
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
270
|
-
const signer = await provider.getSigner();
|
|
271
|
-
const signature = await signer.signMessage(message);
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
**Solana:**
|
|
275
|
-
```typescript
|
|
276
|
-
import { useWallet } from '@solana/wallet-adapter-react';
|
|
277
|
-
import bs58 from 'bs58';
|
|
278
|
-
|
|
279
|
-
const { publicKey, signMessage } = useWallet();
|
|
280
|
-
const encodedMessage = new TextEncoder().encode(message);
|
|
281
|
-
const signatureBuffer = await signMessage(encodedMessage);
|
|
282
|
-
const signature = bs58.encode(signatureBuffer);
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
### 3. Make Authenticated Request
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
const result = await client.getWalletAccounts(
|
|
289
|
-
walletAddress,
|
|
290
|
-
signature,
|
|
291
|
-
message
|
|
292
|
-
);
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
## Common Use Cases
|
|
296
|
-
|
|
297
|
-
### Get Email Accounts
|
|
298
|
-
|
|
299
|
-
```typescript
|
|
300
|
-
const accounts = await client.getWalletAccounts(
|
|
301
|
-
walletAddress,
|
|
302
|
-
signature,
|
|
303
|
-
message
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
if (accounts.success) {
|
|
307
|
-
accounts.data.accounts.forEach(account => {
|
|
308
|
-
console.log('Primary:', account.primaryAccount);
|
|
309
|
-
account.domainAccounts.forEach(domain => {
|
|
310
|
-
console.log('Domain:', domain.account);
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
### Apply Referral Code
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
// Referral code is applied on first /accounts call
|
|
320
|
-
const accounts = await client.getWalletAccounts(
|
|
321
|
-
walletAddress,
|
|
322
|
-
signature,
|
|
323
|
-
message,
|
|
324
|
-
'ABC123XYZ' // Referral code (applied once)
|
|
325
|
-
);
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
### Check Points Balance
|
|
329
|
-
|
|
330
|
-
```typescript
|
|
331
|
-
const points = await client.getPointsBalance(
|
|
332
|
-
walletAddress,
|
|
333
|
-
signature,
|
|
334
|
-
message
|
|
335
|
-
);
|
|
336
|
-
|
|
337
|
-
console.log(`Points: ${points.data.pointsEarned}`);
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
### Generate Referral Code
|
|
341
|
-
|
|
342
|
-
```typescript
|
|
343
|
-
const referral = await client.getReferralCode(
|
|
344
|
-
walletAddress,
|
|
345
|
-
signature,
|
|
346
|
-
message
|
|
347
|
-
);
|
|
348
|
-
|
|
349
|
-
console.log(`Code: ${referral.data.referralCode}`);
|
|
350
|
-
console.log(`Redemptions: ${referral.data.totalRedemptions}`);
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
### Resolve ENS/SNS Name
|
|
354
|
-
|
|
355
|
-
```typescript
|
|
356
|
-
const resolved = await client.resolveNameToAddress('vitalik.eth');
|
|
357
|
-
|
|
358
|
-
if (resolved.success) {
|
|
359
|
-
console.log('Address:', resolved.data.address);
|
|
360
|
-
console.log('Chain:', resolved.data.chainType);
|
|
361
|
-
}
|
|
362
|
-
```
|
|
39
|
+
// Public endpoints (no auth)
|
|
40
|
+
const { data } = useIndexerPointsInfo(networkClient, endpointUrl, dev);
|
|
41
|
+
const { data } = useResolveNameToAddress(networkClient, endpointUrl, dev, 'vitalik.eth');
|
|
363
42
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
Enable development mode to use mock data:
|
|
367
|
-
|
|
368
|
-
```typescript
|
|
369
|
-
const client = new IndexerClient('https://indexer.example.com', true); // dev = true
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
Mock data is defined in `src/hooks/mocks.ts`.
|
|
373
|
-
|
|
374
|
-
## Error Handling
|
|
375
|
-
|
|
376
|
-
All API responses follow this structure:
|
|
377
|
-
|
|
378
|
-
```typescript
|
|
379
|
-
interface ApiResponse<T> {
|
|
380
|
-
success: boolean;
|
|
381
|
-
data: T | null;
|
|
382
|
-
error?: string;
|
|
383
|
-
timestamp: string;
|
|
384
|
-
}
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
Handle errors consistently:
|
|
388
|
-
|
|
389
|
-
```typescript
|
|
390
|
-
const result = await client.someMethod();
|
|
391
|
-
|
|
392
|
-
if (!result.success) {
|
|
393
|
-
console.error('Error:', result.error);
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Use result.data
|
|
43
|
+
// Authenticated endpoints (wallet signature required)
|
|
44
|
+
const { data } = useIndexerGetWalletAccounts(networkClient, endpointUrl, dev, walletAddress, auth);
|
|
398
45
|
```
|
|
399
46
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
All types must be imported from `@sudobility/types`:
|
|
47
|
+
### Utility Helpers
|
|
403
48
|
|
|
404
49
|
```typescript
|
|
405
|
-
import
|
|
406
|
-
AddressValidationResponse,
|
|
407
|
-
EmailAccountsResponse,
|
|
408
|
-
PointsResponse,
|
|
409
|
-
ReferralCodeResponse,
|
|
410
|
-
LeaderboardResponse,
|
|
411
|
-
Optional,
|
|
412
|
-
// ... and more
|
|
413
|
-
} from '@sudobility/types';
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
**Important:** As of version 0.0.26, this library no longer re-exports types from `@sudobility/types`. You must import types directly from `@sudobility/types`:
|
|
417
|
-
|
|
418
|
-
```typescript
|
|
419
|
-
// ✅ Correct
|
|
420
|
-
import type { PointsResponse } from '@sudobility/types';
|
|
421
|
-
import { useIndexerPoints } from '@sudobility/indexer_client';
|
|
422
|
-
|
|
423
|
-
// ❌ Incorrect (will cause errors)
|
|
424
|
-
import type { PointsResponse } from '@sudobility/indexer_client';
|
|
425
|
-
```
|
|
50
|
+
import { createIndexerHelpers } from '@sudobility/indexer_client';
|
|
426
51
|
|
|
427
|
-
|
|
52
|
+
const { admin, graphql, webhook } = createIndexerHelpers(config, networkClient);
|
|
428
53
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
# Run unit tests
|
|
433
|
-
npm test
|
|
434
|
-
|
|
435
|
-
# Run unit tests once
|
|
436
|
-
npm run test:run
|
|
437
|
-
|
|
438
|
-
# Run with coverage
|
|
439
|
-
npm run test:coverage
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
### Integration Tests
|
|
443
|
-
|
|
444
|
-
Integration tests run against a real indexer endpoint. See [src/__integration__/README.md](src/__integration__/README.md) for details.
|
|
445
|
-
|
|
446
|
-
```bash
|
|
447
|
-
# Setup
|
|
448
|
-
cp .env.example .env.test
|
|
449
|
-
# Edit .env.test and set INTEGRATION_TEST_INDEXER_URL
|
|
450
|
-
|
|
451
|
-
# Run integration tests
|
|
452
|
-
npm run test:integration
|
|
453
|
-
|
|
454
|
-
# Run integration tests in watch mode
|
|
455
|
-
npm run test:integration:watch
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
### Other Commands
|
|
459
|
-
|
|
460
|
-
```bash
|
|
461
|
-
# Type checking
|
|
462
|
-
npm run typecheck
|
|
463
|
-
|
|
464
|
-
# Linting
|
|
465
|
-
npm run lint
|
|
466
|
-
|
|
467
|
-
# All checks (lint + typecheck + unit tests)
|
|
468
|
-
npm run check-all
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
## Building
|
|
472
|
-
|
|
473
|
-
```bash
|
|
474
|
-
# Build for production
|
|
475
|
-
npm run build
|
|
476
|
-
|
|
477
|
-
# Build and watch
|
|
478
|
-
npm run build:watch
|
|
479
|
-
|
|
480
|
-
# Clean build artifacts
|
|
481
|
-
npm run clean
|
|
54
|
+
// Admin: campaigns, points awards, user flags
|
|
55
|
+
// GraphQL: mails, delegations, statistics
|
|
56
|
+
// Webhook: email-sent, login, referral events
|
|
482
57
|
```
|
|
483
58
|
|
|
484
|
-
##
|
|
485
|
-
|
|
486
|
-
### v0.1.0 (Current)
|
|
487
|
-
- ✅ Core mail and user management
|
|
488
|
-
- ✅ Points system
|
|
489
|
-
- ✅ Referral system
|
|
490
|
-
- ✅ Name service integration
|
|
491
|
-
- ✅ React hooks
|
|
492
|
-
|
|
493
|
-
### v1.0.0 (Planned)
|
|
494
|
-
- [ ] Complete OAuth 2.0 flow
|
|
495
|
-
- [ ] Block status monitoring
|
|
496
|
-
- [ ] Authentication status check
|
|
497
|
-
- [ ] Enhanced GraphQL support
|
|
498
|
-
|
|
499
|
-
### v1.1.0 (Future)
|
|
500
|
-
- [ ] KYC verification module
|
|
501
|
-
- [ ] Solana admin tools
|
|
502
|
-
- [ ] Advanced caching strategies
|
|
503
|
-
- [ ] Request deduplication
|
|
504
|
-
|
|
505
|
-
See [docs/COVERAGE.md](docs/COVERAGE.md) for detailed implementation status.
|
|
506
|
-
|
|
507
|
-
## CI/CD
|
|
59
|
+
## API
|
|
508
60
|
|
|
509
|
-
|
|
61
|
+
| Export | Description |
|
|
62
|
+
|--------|-------------|
|
|
63
|
+
| `IndexerClient` | Core REST API client (~40 endpoints) |
|
|
64
|
+
| `IndexerService` | Singleton with 5-min in-memory cache (public endpoints) |
|
|
65
|
+
| `useIndexer*` hooks | 18 individual TanStack React Query hooks |
|
|
66
|
+
| `IndexerMockData` | Static mock factories for all response types |
|
|
67
|
+
| `IndexerAdminHelper` | Admin API helper (campaigns, points, flags) |
|
|
68
|
+
| `IndexerGraphQLHelper` | GraphQL query helper (mails, delegations, stats) |
|
|
69
|
+
| `IndexerWebhookHelper` | Webhook processing helper |
|
|
70
|
+
| `createAuthHeaders` | Build signature auth headers (`x-signature`, `x-message`, `x-signer`) |
|
|
510
71
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
On every push to `main`:
|
|
514
|
-
1. ✅ Run tests on Node.js 20.x and 22.x
|
|
515
|
-
2. ✅ Type checking and linting
|
|
516
|
-
3. ✅ Build verification
|
|
517
|
-
4. ✅ Create GitHub release
|
|
518
|
-
5. ✅ Publish to NPM
|
|
519
|
-
|
|
520
|
-
### Triggering a Release
|
|
72
|
+
## Development
|
|
521
73
|
|
|
522
74
|
```bash
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
#
|
|
527
|
-
|
|
75
|
+
bun install
|
|
76
|
+
bun run check-all # lint + typecheck + test:run
|
|
77
|
+
bun run build # TypeScript compilation
|
|
78
|
+
bun run test # Vitest (watch mode)
|
|
79
|
+
bun run test:run # Single run
|
|
80
|
+
bun run test:coverage # Coverage (70% threshold)
|
|
81
|
+
bun run test:integration # Integration tests (requires live indexer)
|
|
82
|
+
bun run typecheck # tsc --noEmit
|
|
83
|
+
bun run lint # ESLint
|
|
528
84
|
```
|
|
529
85
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
## Contributing
|
|
533
|
-
|
|
534
|
-
See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines.
|
|
86
|
+
## Related Packages
|
|
535
87
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
- Blockchain indexing (Ponder framework)
|
|
542
|
-
- REST API (Hono framework)
|
|
543
|
-
- GraphQL API
|
|
544
|
-
- OAuth 2.0 server
|
|
545
|
-
- KYC integration (Sumsub)
|
|
546
|
-
- Multi-chain support (EVM + Solana)
|
|
547
|
-
|
|
548
|
-
## Architecture
|
|
549
|
-
|
|
550
|
-
```
|
|
551
|
-
┌─────────────────────────────────────────────────────┐
|
|
552
|
-
│ React Application │
|
|
553
|
-
│ │
|
|
554
|
-
│ ┌────────────────────────────────────────────────┐ │
|
|
555
|
-
│ │ React Query Hooks │ │
|
|
556
|
-
│ │ useIndexerMail, useIndexerPoints, etc. │ │
|
|
557
|
-
│ └────────────────────────────────────────────────┘ │
|
|
558
|
-
│ ↓ │
|
|
559
|
-
│ ┌────────────────────────────────────────────────┐ │
|
|
560
|
-
│ │ Business Services │ │
|
|
561
|
-
│ │ IndexerService, IndexerAdminHelper, etc. │ │
|
|
562
|
-
│ └────────────────────────────────────────────────┘ │
|
|
563
|
-
│ ↓ │
|
|
564
|
-
│ ┌────────────────────────────────────────────────┐ │
|
|
565
|
-
│ │ IndexerClient (HTTP) │ │
|
|
566
|
-
│ │ axios │ │
|
|
567
|
-
│ └────────────────────────────────────────────────┘ │
|
|
568
|
-
└─────────────────────────────────────────────────────┘
|
|
569
|
-
↓
|
|
570
|
-
┌─────────────────────────────────────────────────────┐
|
|
571
|
-
│ mail_box_indexer Backend │
|
|
572
|
-
│ │
|
|
573
|
-
│ REST API (Hono) + GraphQL + OAuth 2.0 │
|
|
574
|
-
│ PostgreSQL Database (Ponder framework) │
|
|
575
|
-
│ Multi-chain indexing (EVM + Solana) │
|
|
576
|
-
└─────────────────────────────────────────────────────┘
|
|
577
|
-
```
|
|
88
|
+
- `@0xmail/indexer` -- the backend this client connects to
|
|
89
|
+
- `@sudobility/di` -- provides `NetworkClient` interface
|
|
90
|
+
- `@sudobility/mail_box_types` -- shared API response types
|
|
91
|
+
- `@sudobility/types` -- core types (ChainType, Optional)
|
|
92
|
+
- `@sudobility/configs` -- application configuration
|
|
578
93
|
|
|
579
94
|
## License
|
|
580
95
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
## Support
|
|
584
|
-
|
|
585
|
-
For questions and support:
|
|
586
|
-
- GitHub Issues: https://github.com/johnqh/mail_box_indexer_client/issues
|
|
587
|
-
- Documentation: See `docs/API.md` and `docs/EXAMPLES.md`
|
|
588
|
-
- Backend: `../mail_box_indexer`
|
|
589
|
-
|
|
590
|
-
## Version
|
|
591
|
-
|
|
592
|
-
Current version: **0.0.28**
|
|
593
|
-
|
|
594
|
-
See [docs/COVERAGE.md](docs/COVERAGE.md) for implementation roadmap.
|
|
96
|
+
BUSL-1.1
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sudobility/indexer_client",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.120",
|
|
4
4
|
"description": "React and React Native compatible client library for blockchain mail indexer API with TypeScript support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -42,18 +42,18 @@
|
|
|
42
42
|
"author": "John Huang",
|
|
43
43
|
"license": "BUSL-1.1",
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@sudobility/di": "^1.5.
|
|
46
|
-
"@sudobility/mail_box_types": "^1.0.
|
|
47
|
-
"@sudobility/types": "^1.9.
|
|
45
|
+
"@sudobility/di": "^1.5.45",
|
|
46
|
+
"@sudobility/mail_box_types": "^1.0.16",
|
|
47
|
+
"@sudobility/types": "^1.9.57",
|
|
48
48
|
"@tanstack/react-query": ">=5.0.0",
|
|
49
49
|
"react": ">=18.0.0",
|
|
50
|
-
"@sudobility/configs": "^0.0.
|
|
50
|
+
"@sudobility/configs": "^0.0.68"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@sudobility/configs": "^0.0.
|
|
54
|
-
"@sudobility/di": "^1.5.
|
|
55
|
-
"@sudobility/mail_box_types": "^1.0.
|
|
56
|
-
"@sudobility/types": "^1.9.
|
|
53
|
+
"@sudobility/configs": "^0.0.68",
|
|
54
|
+
"@sudobility/di": "^1.5.45",
|
|
55
|
+
"@sudobility/mail_box_types": "^1.0.16",
|
|
56
|
+
"@sudobility/types": "^1.9.57",
|
|
57
57
|
"@tanstack/react-query": "^5.90.5",
|
|
58
58
|
"@testing-library/dom": "^10.4.1",
|
|
59
59
|
"@testing-library/react": "^16.3.0",
|