@johnqh/indexer_client 0.0.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 +576 -0
- package/dist/business/index.d.ts +2 -0
- package/dist/business/index.d.ts.map +1 -0
- package/dist/business/index.js +2 -0
- package/dist/business/index.js.map +1 -0
- package/dist/business/indexer-service.d.ts +27 -0
- package/dist/business/indexer-service.d.ts.map +1 -0
- package/dist/business/indexer-service.js +74 -0
- package/dist/business/indexer-service.js.map +1 -0
- package/dist/hooks/index.d.ts +9 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +9 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/mocks.d.ts +15 -0
- package/dist/hooks/mocks.d.ts.map +1 -0
- package/dist/hooks/mocks.js +163 -0
- package/dist/hooks/mocks.js.map +1 -0
- package/dist/hooks/useIndexerMail.d.ts +20 -0
- package/dist/hooks/useIndexerMail.d.ts.map +1 -0
- package/dist/hooks/useIndexerMail.js +160 -0
- package/dist/hooks/useIndexerMail.js.map +1 -0
- package/dist/hooks/useIndexerNameService.d.ts +5 -0
- package/dist/hooks/useIndexerNameService.d.ts.map +1 -0
- package/dist/hooks/useIndexerNameService.js +30 -0
- package/dist/hooks/useIndexerNameService.js.map +1 -0
- package/dist/hooks/useIndexerPoints.d.ts +10 -0
- package/dist/hooks/useIndexerPoints.d.ts.map +1 -0
- package/dist/hooks/useIndexerPoints.js +100 -0
- package/dist/hooks/useIndexerPoints.js.map +1 -0
- package/dist/hooks/useReferralCode.d.ts +11 -0
- package/dist/hooks/useReferralCode.d.ts.map +1 -0
- package/dist/hooks/useReferralCode.js +42 -0
- package/dist/hooks/useReferralCode.js.map +1 -0
- package/dist/hooks/useReferralConsumption.d.ts +9 -0
- package/dist/hooks/useReferralConsumption.d.ts.map +1 -0
- package/dist/hooks/useReferralConsumption.js +49 -0
- package/dist/hooks/useReferralConsumption.js.map +1 -0
- package/dist/hooks/useReferralShare.d.ts +7 -0
- package/dist/hooks/useReferralShare.d.ts.map +1 -0
- package/dist/hooks/useReferralShare.js +18 -0
- package/dist/hooks/useReferralShare.js.map +1 -0
- package/dist/hooks/useReferralStats.d.ts +11 -0
- package/dist/hooks/useReferralStats.d.ts.map +1 -0
- package/dist/hooks/useReferralStats.js +42 -0
- package/dist/hooks/useReferralStats.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/network/IndexerClient.d.ts +77 -0
- package/dist/network/IndexerClient.d.ts.map +1 -0
- package/dist/network/IndexerClient.js +258 -0
- package/dist/network/IndexerClient.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/indexer-admin.d.ts +106 -0
- package/dist/utils/indexer-admin.d.ts.map +1 -0
- package/dist/utils/indexer-admin.js +112 -0
- package/dist/utils/indexer-admin.js.map +1 -0
- package/dist/utils/indexer-factory.d.ts +13 -0
- package/dist/utils/indexer-factory.d.ts.map +1 -0
- package/dist/utils/indexer-factory.js +24 -0
- package/dist/utils/indexer-factory.js.map +1 -0
- package/dist/utils/indexer-graphql.d.ts +152 -0
- package/dist/utils/indexer-graphql.d.ts.map +1 -0
- package/dist/utils/indexer-graphql.js +210 -0
- package/dist/utils/indexer-graphql.js.map +1 -0
- package/dist/utils/indexer-webhooks.d.ts +60 -0
- package/dist/utils/indexer-webhooks.d.ts.map +1 -0
- package/dist/utils/indexer-webhooks.js +68 -0
- package/dist/utils/indexer-webhooks.js.map +1 -0
- package/package.json +72 -0
package/README.md
ADDED
@@ -0,0 +1,576 @@
|
|
1
|
+
# @johnqh/indexer_client
|
2
|
+
|
3
|
+
TypeScript client library for the 0xMail Indexer API. Compatible with React and React Native applications.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- ✅ **Complete Type Safety** - Full TypeScript support with `@johnqh/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
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
```bash
|
20
|
+
npm install @johnqh/indexer_client
|
21
|
+
```
|
22
|
+
|
23
|
+
### Peer Dependencies
|
24
|
+
|
25
|
+
```bash
|
26
|
+
npm install react @tanstack/react-query axios
|
27
|
+
```
|
28
|
+
|
29
|
+
## Quick Start
|
30
|
+
|
31
|
+
### 1. Setup React Query
|
32
|
+
|
33
|
+
```typescript
|
34
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
35
|
+
|
36
|
+
const queryClient = new QueryClient({
|
37
|
+
defaultOptions: {
|
38
|
+
queries: {
|
39
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
40
|
+
},
|
41
|
+
},
|
42
|
+
});
|
43
|
+
|
44
|
+
function App() {
|
45
|
+
return (
|
46
|
+
<QueryClientProvider client={queryClient}>
|
47
|
+
{/* Your app */}
|
48
|
+
</QueryClientProvider>
|
49
|
+
);
|
50
|
+
}
|
51
|
+
```
|
52
|
+
|
53
|
+
### 2. Use Hooks
|
54
|
+
|
55
|
+
```typescript
|
56
|
+
import { useIndexerPoints } from '@johnqh/indexer_client';
|
57
|
+
|
58
|
+
function PointsDisplay({ wallet, signature, message }) {
|
59
|
+
const { data, isLoading } = useIndexerPoints(
|
60
|
+
'https://indexer.0xmail.box',
|
61
|
+
false, // dev mode
|
62
|
+
wallet,
|
63
|
+
signature,
|
64
|
+
message
|
65
|
+
);
|
66
|
+
|
67
|
+
if (isLoading) return <div>Loading...</div>;
|
68
|
+
if (!data?.success) return <div>Error</div>;
|
69
|
+
|
70
|
+
return <div>Points: {data.data.pointsEarned}</div>;
|
71
|
+
}
|
72
|
+
```
|
73
|
+
|
74
|
+
## API Coverage
|
75
|
+
|
76
|
+
| Feature | Status | Endpoints |
|
77
|
+
|---------|--------|-----------|
|
78
|
+
| Mail & User Management | ✅ 71% | 12/17 implemented |
|
79
|
+
| Points System | ✅ 100% | 3/3 implemented |
|
80
|
+
| Referral System | ✅ 100% | Fully implemented |
|
81
|
+
| OAuth 2.0 | ❌ 0% | Planned for v1.0 |
|
82
|
+
| KYC Verification | ❌ 0% | Optional feature |
|
83
|
+
| Solana Admin | ❌ 0% | Admin tools |
|
84
|
+
|
85
|
+
See [COVERAGE.md](COVERAGE.md) for complete endpoint matrix.
|
86
|
+
|
87
|
+
## Documentation
|
88
|
+
|
89
|
+
- **[API.md](API.md)** - Complete API endpoint documentation
|
90
|
+
- **[EXAMPLES.md](EXAMPLES.md)** - Code examples for all features
|
91
|
+
- **[AI_DEVELOPMENT_GUIDE.md](AI_DEVELOPMENT_GUIDE.md)** - Guide for AI-assisted development
|
92
|
+
- **[COVERAGE.md](COVERAGE.md)** - API implementation status
|
93
|
+
|
94
|
+
## Core Components
|
95
|
+
|
96
|
+
### IndexerClient
|
97
|
+
|
98
|
+
Low-level HTTP client for direct API access:
|
99
|
+
|
100
|
+
```typescript
|
101
|
+
import { IndexerClient } from '@johnqh/indexer_client';
|
102
|
+
|
103
|
+
const client = new IndexerClient('https://indexer.0xmail.box', false);
|
104
|
+
|
105
|
+
// Validate wallet address
|
106
|
+
const result = await client.validateUsername('0x742d35Cc...');
|
107
|
+
|
108
|
+
// Get signing message
|
109
|
+
const msgResult = await client.getMessage(
|
110
|
+
'0x742d35Cc...',
|
111
|
+
1, // chainId
|
112
|
+
'0xmail.box',
|
113
|
+
'https://0xmail.box'
|
114
|
+
);
|
115
|
+
|
116
|
+
// Get points balance (requires signature)
|
117
|
+
const points = await client.getPointsBalance(wallet, signature, message);
|
118
|
+
```
|
119
|
+
|
120
|
+
### React Hooks
|
121
|
+
|
122
|
+
High-level hooks with automatic caching and refetching:
|
123
|
+
|
124
|
+
#### useIndexerMail
|
125
|
+
```typescript
|
126
|
+
import { useIndexerMail } from '@johnqh/indexer_client';
|
127
|
+
|
128
|
+
const { data, isLoading, error, refetch } = useIndexerMail(
|
129
|
+
endpointUrl,
|
130
|
+
dev,
|
131
|
+
walletAddress,
|
132
|
+
signature,
|
133
|
+
message
|
134
|
+
);
|
135
|
+
```
|
136
|
+
|
137
|
+
#### useIndexerPoints
|
138
|
+
```typescript
|
139
|
+
import { useIndexerPoints } from '@johnqh/indexer_client';
|
140
|
+
|
141
|
+
const { data, isLoading } = useIndexerPoints(
|
142
|
+
endpointUrl,
|
143
|
+
dev,
|
144
|
+
walletAddress,
|
145
|
+
signature,
|
146
|
+
message
|
147
|
+
);
|
148
|
+
```
|
149
|
+
|
150
|
+
#### useReferralCode
|
151
|
+
```typescript
|
152
|
+
import { useReferralCode } from '@johnqh/indexer_client';
|
153
|
+
|
154
|
+
const { data, isLoading } = useReferralCode(
|
155
|
+
endpointUrl,
|
156
|
+
dev,
|
157
|
+
walletAddress,
|
158
|
+
signature,
|
159
|
+
message
|
160
|
+
);
|
161
|
+
```
|
162
|
+
|
163
|
+
#### useReferralStats
|
164
|
+
```typescript
|
165
|
+
import { useReferralStats } from '@johnqh/indexer_client';
|
166
|
+
|
167
|
+
const { data, isLoading } = useReferralStats(
|
168
|
+
endpointUrl,
|
169
|
+
dev,
|
170
|
+
referralCode
|
171
|
+
);
|
172
|
+
```
|
173
|
+
|
174
|
+
#### useWalletNames / useResolveNameToAddress
|
175
|
+
```typescript
|
176
|
+
import { useWalletNames, useResolveNameToAddress } from '@johnqh/indexer_client';
|
177
|
+
|
178
|
+
// Get all names for a wallet
|
179
|
+
const { data: names } = useWalletNames(
|
180
|
+
endpointUrl,
|
181
|
+
dev,
|
182
|
+
walletAddress,
|
183
|
+
signature,
|
184
|
+
message
|
185
|
+
);
|
186
|
+
|
187
|
+
// Resolve name to address
|
188
|
+
const { data: resolved } = useResolveNameToAddress(
|
189
|
+
endpointUrl,
|
190
|
+
dev,
|
191
|
+
'vitalik.eth'
|
192
|
+
);
|
193
|
+
```
|
194
|
+
|
195
|
+
### Business Services
|
196
|
+
|
197
|
+
#### IndexerService
|
198
|
+
Caching wrapper for public endpoints:
|
199
|
+
|
200
|
+
```typescript
|
201
|
+
import { IndexerService } from '@johnqh/indexer_client';
|
202
|
+
|
203
|
+
const config = {
|
204
|
+
indexerBackendUrl: 'https://indexer.0xmail.box'
|
205
|
+
};
|
206
|
+
|
207
|
+
const service = IndexerService.getInstance(config);
|
208
|
+
|
209
|
+
// Get leaderboard (cached for 5 minutes)
|
210
|
+
const leaderboard = await service.getLeaderboard(10);
|
211
|
+
|
212
|
+
// Get public stats
|
213
|
+
const stats = await service.getPublicStats();
|
214
|
+
```
|
215
|
+
|
216
|
+
### Factory Helpers
|
217
|
+
|
218
|
+
Create helper instances with automatic client injection:
|
219
|
+
|
220
|
+
```typescript
|
221
|
+
import {
|
222
|
+
createIndexerAdmin,
|
223
|
+
createIndexerGraphQL,
|
224
|
+
createIndexerWebhook,
|
225
|
+
createIndexerHelpers
|
226
|
+
} from '@johnqh/indexer_client';
|
227
|
+
|
228
|
+
const config = {
|
229
|
+
indexerBackendUrl: 'https://indexer.0xmail.box'
|
230
|
+
};
|
231
|
+
|
232
|
+
// Create individual helpers
|
233
|
+
const admin = createIndexerAdmin(config);
|
234
|
+
const graphql = createIndexerGraphQL(config);
|
235
|
+
const webhook = createIndexerWebhook(config);
|
236
|
+
|
237
|
+
// Or create all at once
|
238
|
+
const { admin, graphql, webhook } = createIndexerHelpers(config);
|
239
|
+
```
|
240
|
+
|
241
|
+
## Authentication
|
242
|
+
|
243
|
+
All protected endpoints require signature authentication:
|
244
|
+
|
245
|
+
### 1. Generate Message
|
246
|
+
|
247
|
+
```typescript
|
248
|
+
const msgResult = await client.getMessage(
|
249
|
+
walletAddress,
|
250
|
+
chainId,
|
251
|
+
'domain.com',
|
252
|
+
'https://domain.com'
|
253
|
+
);
|
254
|
+
const message = msgResult.data.message;
|
255
|
+
```
|
256
|
+
|
257
|
+
### 2. Sign Message
|
258
|
+
|
259
|
+
**EVM (ethers.js):**
|
260
|
+
```typescript
|
261
|
+
import { ethers } from 'ethers';
|
262
|
+
|
263
|
+
const provider = new ethers.BrowserProvider(window.ethereum);
|
264
|
+
const signer = await provider.getSigner();
|
265
|
+
const signature = await signer.signMessage(message);
|
266
|
+
```
|
267
|
+
|
268
|
+
**Solana:**
|
269
|
+
```typescript
|
270
|
+
import { useWallet } from '@solana/wallet-adapter-react';
|
271
|
+
import bs58 from 'bs58';
|
272
|
+
|
273
|
+
const { publicKey, signMessage } = useWallet();
|
274
|
+
const encodedMessage = new TextEncoder().encode(message);
|
275
|
+
const signatureBuffer = await signMessage(encodedMessage);
|
276
|
+
const signature = bs58.encode(signatureBuffer);
|
277
|
+
```
|
278
|
+
|
279
|
+
### 3. Make Authenticated Request
|
280
|
+
|
281
|
+
```typescript
|
282
|
+
const result = await client.getWalletAccounts(
|
283
|
+
walletAddress,
|
284
|
+
signature,
|
285
|
+
message
|
286
|
+
);
|
287
|
+
```
|
288
|
+
|
289
|
+
## Common Use Cases
|
290
|
+
|
291
|
+
### Get Email Accounts
|
292
|
+
|
293
|
+
```typescript
|
294
|
+
const accounts = await client.getWalletAccounts(
|
295
|
+
walletAddress,
|
296
|
+
signature,
|
297
|
+
message
|
298
|
+
);
|
299
|
+
|
300
|
+
if (accounts.success) {
|
301
|
+
accounts.data.accounts.forEach(account => {
|
302
|
+
console.log('Primary:', account.primaryAccount);
|
303
|
+
account.domainAccounts.forEach(domain => {
|
304
|
+
console.log('Domain:', domain.account);
|
305
|
+
});
|
306
|
+
});
|
307
|
+
}
|
308
|
+
```
|
309
|
+
|
310
|
+
### Apply Referral Code
|
311
|
+
|
312
|
+
```typescript
|
313
|
+
// Referral code is applied on first /accounts call
|
314
|
+
const accounts = await client.getWalletAccounts(
|
315
|
+
walletAddress,
|
316
|
+
signature,
|
317
|
+
message,
|
318
|
+
'ABC123XYZ' // Referral code (applied once)
|
319
|
+
);
|
320
|
+
```
|
321
|
+
|
322
|
+
### Check Points Balance
|
323
|
+
|
324
|
+
```typescript
|
325
|
+
const points = await client.getPointsBalance(
|
326
|
+
walletAddress,
|
327
|
+
signature,
|
328
|
+
message
|
329
|
+
);
|
330
|
+
|
331
|
+
console.log(`Points: ${points.data.pointsEarned}`);
|
332
|
+
```
|
333
|
+
|
334
|
+
### Generate Referral Code
|
335
|
+
|
336
|
+
```typescript
|
337
|
+
const referral = await client.getReferralCode(
|
338
|
+
walletAddress,
|
339
|
+
signature,
|
340
|
+
message
|
341
|
+
);
|
342
|
+
|
343
|
+
console.log(`Code: ${referral.data.referralCode}`);
|
344
|
+
console.log(`Redemptions: ${referral.data.totalRedemptions}`);
|
345
|
+
```
|
346
|
+
|
347
|
+
### Resolve ENS/SNS Name
|
348
|
+
|
349
|
+
```typescript
|
350
|
+
const resolved = await client.resolveNameToAddress('vitalik.eth');
|
351
|
+
|
352
|
+
if (resolved.success) {
|
353
|
+
console.log('Address:', resolved.data.address);
|
354
|
+
console.log('Chain:', resolved.data.chainType);
|
355
|
+
}
|
356
|
+
```
|
357
|
+
|
358
|
+
## Development Mode
|
359
|
+
|
360
|
+
Enable development mode to use mock data:
|
361
|
+
|
362
|
+
```typescript
|
363
|
+
const client = new IndexerClient('https://indexer.0xmail.box', true); // dev = true
|
364
|
+
```
|
365
|
+
|
366
|
+
Mock data is defined in `src/hooks/mocks.ts`.
|
367
|
+
|
368
|
+
## Error Handling
|
369
|
+
|
370
|
+
All API responses follow this structure:
|
371
|
+
|
372
|
+
```typescript
|
373
|
+
interface ApiResponse<T> {
|
374
|
+
success: boolean;
|
375
|
+
data: T | null;
|
376
|
+
error?: string;
|
377
|
+
timestamp: string;
|
378
|
+
}
|
379
|
+
```
|
380
|
+
|
381
|
+
Handle errors consistently:
|
382
|
+
|
383
|
+
```typescript
|
384
|
+
const result = await client.someMethod();
|
385
|
+
|
386
|
+
if (!result.success) {
|
387
|
+
console.error('Error:', result.error);
|
388
|
+
return;
|
389
|
+
}
|
390
|
+
|
391
|
+
// Use result.data
|
392
|
+
```
|
393
|
+
|
394
|
+
## TypeScript Support
|
395
|
+
|
396
|
+
All types are imported from `@johnqh/types`:
|
397
|
+
|
398
|
+
```typescript
|
399
|
+
import type {
|
400
|
+
AddressValidationResponse,
|
401
|
+
EmailAccountsResponse,
|
402
|
+
PointsResponse,
|
403
|
+
ReferralCodeResponse,
|
404
|
+
LeaderboardResponse,
|
405
|
+
// ... and more
|
406
|
+
} from '@johnqh/indexer_client';
|
407
|
+
```
|
408
|
+
|
409
|
+
## Testing
|
410
|
+
|
411
|
+
### Unit Tests
|
412
|
+
|
413
|
+
```bash
|
414
|
+
# Run unit tests
|
415
|
+
npm test
|
416
|
+
|
417
|
+
# Run unit tests once
|
418
|
+
npm run test:run
|
419
|
+
|
420
|
+
# Run with coverage
|
421
|
+
npm run test:coverage
|
422
|
+
```
|
423
|
+
|
424
|
+
### Integration Tests
|
425
|
+
|
426
|
+
Integration tests run against a real indexer endpoint. See [src/__integration__/README.md](src/__integration__/README.md) for details.
|
427
|
+
|
428
|
+
```bash
|
429
|
+
# Setup
|
430
|
+
cp .env.example .env.test
|
431
|
+
# Edit .env.test and set INTEGRATION_TEST_INDEXER_URL
|
432
|
+
|
433
|
+
# Run integration tests
|
434
|
+
npm run test:integration
|
435
|
+
|
436
|
+
# Run integration tests in watch mode
|
437
|
+
npm run test:integration:watch
|
438
|
+
```
|
439
|
+
|
440
|
+
### Other Commands
|
441
|
+
|
442
|
+
```bash
|
443
|
+
# Type checking
|
444
|
+
npm run typecheck
|
445
|
+
|
446
|
+
# Linting
|
447
|
+
npm run lint
|
448
|
+
|
449
|
+
# All checks (lint + typecheck + unit tests)
|
450
|
+
npm run check-all
|
451
|
+
```
|
452
|
+
|
453
|
+
## Building
|
454
|
+
|
455
|
+
```bash
|
456
|
+
# Build for production
|
457
|
+
npm run build
|
458
|
+
|
459
|
+
# Build and watch
|
460
|
+
npm run build:watch
|
461
|
+
|
462
|
+
# Clean build artifacts
|
463
|
+
npm run clean
|
464
|
+
```
|
465
|
+
|
466
|
+
## Roadmap
|
467
|
+
|
468
|
+
### v0.1.0 (Current)
|
469
|
+
- ✅ Core mail and user management
|
470
|
+
- ✅ Points system
|
471
|
+
- ✅ Referral system
|
472
|
+
- ✅ Name service integration
|
473
|
+
- ✅ React hooks
|
474
|
+
|
475
|
+
### v1.0.0 (Planned)
|
476
|
+
- [ ] Complete OAuth 2.0 flow
|
477
|
+
- [ ] Block status monitoring
|
478
|
+
- [ ] Authentication status check
|
479
|
+
- [ ] Enhanced GraphQL support
|
480
|
+
|
481
|
+
### v1.1.0 (Future)
|
482
|
+
- [ ] KYC verification module
|
483
|
+
- [ ] Solana admin tools
|
484
|
+
- [ ] Advanced caching strategies
|
485
|
+
- [ ] Request deduplication
|
486
|
+
|
487
|
+
See [COVERAGE.md](COVERAGE.md) for detailed implementation status.
|
488
|
+
|
489
|
+
## CI/CD
|
490
|
+
|
491
|
+
This project uses GitHub Actions for automated testing and releases.
|
492
|
+
|
493
|
+
### Automated Workflow
|
494
|
+
|
495
|
+
On every push to `main`:
|
496
|
+
1. ✅ Run tests on Node.js 20.x and 22.x
|
497
|
+
2. ✅ Type checking and linting
|
498
|
+
3. ✅ Build verification
|
499
|
+
4. ✅ Create GitHub release
|
500
|
+
5. ✅ Publish to NPM
|
501
|
+
|
502
|
+
### Triggering a Release
|
503
|
+
|
504
|
+
```bash
|
505
|
+
# Bump version
|
506
|
+
npm version patch # 0.0.1 -> 0.0.2
|
507
|
+
|
508
|
+
# Push to trigger release
|
509
|
+
git push origin main
|
510
|
+
```
|
511
|
+
|
512
|
+
See [.github/workflows/README.md](.github/workflows/README.md) for detailed CI/CD documentation.
|
513
|
+
|
514
|
+
## Contributing
|
515
|
+
|
516
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
517
|
+
|
518
|
+
## Backend Repository
|
519
|
+
|
520
|
+
This client library connects to the mail_box_indexer backend, located at `../mail_box_indexer`.
|
521
|
+
|
522
|
+
The backend provides:
|
523
|
+
- Blockchain indexing (Ponder framework)
|
524
|
+
- REST API (Hono framework)
|
525
|
+
- GraphQL API
|
526
|
+
- OAuth 2.0 server
|
527
|
+
- KYC integration (Sumsub)
|
528
|
+
- Multi-chain support (EVM + Solana)
|
529
|
+
|
530
|
+
## Architecture
|
531
|
+
|
532
|
+
```
|
533
|
+
┌─────────────────────────────────────────────────────┐
|
534
|
+
│ React Application │
|
535
|
+
│ │
|
536
|
+
│ ┌────────────────────────────────────────────────┐ │
|
537
|
+
│ │ React Query Hooks │ │
|
538
|
+
│ │ useIndexerMail, useIndexerPoints, etc. │ │
|
539
|
+
│ └────────────────────────────────────────────────┘ │
|
540
|
+
│ ↓ │
|
541
|
+
│ ┌────────────────────────────────────────────────┐ │
|
542
|
+
│ │ Business Services │ │
|
543
|
+
│ │ IndexerService, IndexerAdminHelper, etc. │ │
|
544
|
+
│ └────────────────────────────────────────────────┘ │
|
545
|
+
│ ↓ │
|
546
|
+
│ ┌────────────────────────────────────────────────┐ │
|
547
|
+
│ │ IndexerClient (HTTP) │ │
|
548
|
+
│ │ axios │ │
|
549
|
+
│ └────────────────────────────────────────────────┘ │
|
550
|
+
└─────────────────────────────────────────────────────┘
|
551
|
+
↓
|
552
|
+
┌─────────────────────────────────────────────────────┐
|
553
|
+
│ mail_box_indexer Backend │
|
554
|
+
│ │
|
555
|
+
│ REST API (Hono) + GraphQL + OAuth 2.0 │
|
556
|
+
│ PostgreSQL Database (Ponder framework) │
|
557
|
+
│ Multi-chain indexing (EVM + Solana) │
|
558
|
+
└─────────────────────────────────────────────────────┘
|
559
|
+
```
|
560
|
+
|
561
|
+
## License
|
562
|
+
|
563
|
+
MIT
|
564
|
+
|
565
|
+
## Support
|
566
|
+
|
567
|
+
For questions and support:
|
568
|
+
- GitHub Issues: https://github.com/johnqh/mail_box_indexer_client/issues
|
569
|
+
- Documentation: See `API.md` and `EXAMPLES.md`
|
570
|
+
- Backend: `../mail_box_indexer`
|
571
|
+
|
572
|
+
## Version
|
573
|
+
|
574
|
+
Current version: **0.0.1**
|
575
|
+
|
576
|
+
See [COVERAGE.md](COVERAGE.md) for implementation roadmap.
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/business/index.ts"],"names":[],"mappings":"AAIA,cAAc,mBAAmB,CAAC"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/business/index.ts"],"names":[],"mappings":"AAIA,cAAc,mBAAmB,CAAC"}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import type { AppConfig } from '@johnqh/types';
|
2
|
+
interface IndexerLeaderboardResponse {
|
3
|
+
success: boolean;
|
4
|
+
leaderboard?: any[];
|
5
|
+
message?: string;
|
6
|
+
}
|
7
|
+
interface IndexerPublicStatsResponse {
|
8
|
+
success: boolean;
|
9
|
+
stats?: any;
|
10
|
+
message?: string;
|
11
|
+
}
|
12
|
+
declare class IndexerService {
|
13
|
+
private static instance;
|
14
|
+
private indexerClient;
|
15
|
+
private cache;
|
16
|
+
private readonly CACHE_TTL;
|
17
|
+
constructor(config: AppConfig);
|
18
|
+
static getInstance(config: AppConfig): IndexerService;
|
19
|
+
private getCacheKey;
|
20
|
+
private getCache;
|
21
|
+
private setCache;
|
22
|
+
getLeaderboard(count?: number): Promise<IndexerLeaderboardResponse>;
|
23
|
+
getPublicStats(): Promise<IndexerPublicStatsResponse>;
|
24
|
+
clearCache(): void;
|
25
|
+
}
|
26
|
+
export { IndexerService };
|
27
|
+
//# sourceMappingURL=indexer-service.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"indexer-service.d.ts","sourceRoot":"","sources":["../../src/business/indexer-service.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI/C,UAAU,0BAA0B;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,0BAA0B;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAKD,cAAM,cAAc;IAClB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAiB;IACxC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,KAAK,CAAqD;IAClE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;gBAE/B,MAAM,EAAE,SAAS;WAOf,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,cAAc;IAW5D,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,QAAQ;IAcH,cAAc,CACzB,KAAK,GAAE,MAAW,GACjB,OAAO,CAAC,0BAA0B,CAAC;IAyBzB,cAAc,IAAI,OAAO,CAAC,0BAA0B,CAAC;IAyB3D,UAAU,IAAI,IAAI;CAa1B;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import { IndexerClient } from '../network/IndexerClient';
|
2
|
+
class IndexerService {
|
3
|
+
constructor(config) {
|
4
|
+
this.cache = new Map();
|
5
|
+
this.CACHE_TTL = 5 * 60 * 1000;
|
6
|
+
this.indexerClient = new IndexerClient(config.indexerBackendUrl || 'https://indexer.0xmail.box', config.devMode || false);
|
7
|
+
}
|
8
|
+
static getInstance(config) {
|
9
|
+
if (!IndexerService.instance) {
|
10
|
+
IndexerService.instance = new IndexerService(config);
|
11
|
+
}
|
12
|
+
return IndexerService.instance;
|
13
|
+
}
|
14
|
+
getCacheKey(...args) {
|
15
|
+
return args.join(':');
|
16
|
+
}
|
17
|
+
getCache(key) {
|
18
|
+
const cached = this.cache.get(key);
|
19
|
+
if (cached && cached.expires > Date.now()) {
|
20
|
+
return cached.data;
|
21
|
+
}
|
22
|
+
this.cache.delete(key);
|
23
|
+
return null;
|
24
|
+
}
|
25
|
+
setCache(key, data) {
|
26
|
+
this.cache.set(key, {
|
27
|
+
data,
|
28
|
+
expires: Date.now() + this.CACHE_TTL,
|
29
|
+
});
|
30
|
+
}
|
31
|
+
async getLeaderboard(count = 10) {
|
32
|
+
const cacheKey = this.getCacheKey('leaderboard', count);
|
33
|
+
const cached = this.getCache(cacheKey);
|
34
|
+
if (cached)
|
35
|
+
return cached;
|
36
|
+
try {
|
37
|
+
const response = await this.indexerClient.getPointsLeaderboard(count);
|
38
|
+
const result = {
|
39
|
+
success: true,
|
40
|
+
leaderboard: response.data?.leaderboard || [],
|
41
|
+
};
|
42
|
+
this.setCache(cacheKey, result);
|
43
|
+
return result;
|
44
|
+
}
|
45
|
+
catch (error) {
|
46
|
+
console.error('Failed to get leaderboard:', error);
|
47
|
+
return { success: false, message: 'Failed to get leaderboard' };
|
48
|
+
}
|
49
|
+
}
|
50
|
+
async getPublicStats() {
|
51
|
+
const cacheKey = this.getCacheKey('public-stats');
|
52
|
+
const cached = this.getCache(cacheKey);
|
53
|
+
if (cached)
|
54
|
+
return cached;
|
55
|
+
try {
|
56
|
+
const response = await this.indexerClient.getPointsSiteStats();
|
57
|
+
const result = {
|
58
|
+
success: true,
|
59
|
+
stats: response.data,
|
60
|
+
};
|
61
|
+
this.setCache(cacheKey, result);
|
62
|
+
return result;
|
63
|
+
}
|
64
|
+
catch (error) {
|
65
|
+
console.error('Failed to get public stats:', error);
|
66
|
+
return { success: false, message: 'Failed to get public stats' };
|
67
|
+
}
|
68
|
+
}
|
69
|
+
clearCache() {
|
70
|
+
this.cache.clear();
|
71
|
+
}
|
72
|
+
}
|
73
|
+
export { IndexerService };
|
74
|
+
//# sourceMappingURL=indexer-service.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"indexer-service.js","sourceRoot":"","sources":["../../src/business/indexer-service.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
export * from './useIndexerPoints';
|
2
|
+
export * from './useIndexerMail';
|
3
|
+
export { useWalletNames, useResolveNameToAddress, } from './useIndexerNameService';
|
4
|
+
export * from './useReferralCode';
|
5
|
+
export * from './useReferralShare';
|
6
|
+
export * from './useReferralConsumption';
|
7
|
+
export * from './useReferralStats';
|
8
|
+
export { IndexerMockData } from './mocks';
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|