krawlet-js 1.0.0
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 +436 -0
- package/dist/index.cjs +615 -0
- package/dist/index.d.cts +362 -0
- package/dist/index.d.ts +362 -0
- package/dist/index.js +579 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
# krawlet-js
|
|
2
|
+
|
|
3
|
+
> TypeScript/JavaScript client library for the Krawlet Minecraft economy tracking API
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/krawlet-js)
|
|
6
|
+
[](https://opensource.org/licenses/ISC)
|
|
7
|
+
|
|
8
|
+
## Table of Contents
|
|
9
|
+
|
|
10
|
+
- [Installation](#installation)
|
|
11
|
+
- [Quick Start](#quick-start)
|
|
12
|
+
- [Configuration](#configuration)
|
|
13
|
+
- [API Reference](#api-reference)
|
|
14
|
+
- [Health](#health)
|
|
15
|
+
- [Players](#players)
|
|
16
|
+
- [Shops](#shops)
|
|
17
|
+
- [Items](#items)
|
|
18
|
+
- [Addresses](#addresses)
|
|
19
|
+
- [Storage](#storage)
|
|
20
|
+
- [Reports](#reports)
|
|
21
|
+
- [Error Handling](#error-handling)
|
|
22
|
+
- [Rate Limiting](#rate-limiting)
|
|
23
|
+
- [TypeScript Support](#typescript-support)
|
|
24
|
+
- [Examples](#examples)
|
|
25
|
+
- [Development](#development)
|
|
26
|
+
- [License](#license)
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Using pnpm
|
|
32
|
+
pnpm add krawlet-js
|
|
33
|
+
|
|
34
|
+
# Using npm
|
|
35
|
+
npm install krawlet-js
|
|
36
|
+
|
|
37
|
+
# Using yarn
|
|
38
|
+
yarn add krawlet-js
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Requirements:**
|
|
42
|
+
- Node.js 18.x or higher (for native `fetch` support)
|
|
43
|
+
- TypeScript 5.x (optional, but recommended)
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { KrawletClient } from 'krawlet-js';
|
|
49
|
+
|
|
50
|
+
// Create a client (anonymous - 100 requests/hour)
|
|
51
|
+
const client = new KrawletClient();
|
|
52
|
+
|
|
53
|
+
// Get all shops
|
|
54
|
+
const shops = await client.shops.getAll();
|
|
55
|
+
console.log(`Found ${shops.length} shops`);
|
|
56
|
+
|
|
57
|
+
// Find a player by Kromer address
|
|
58
|
+
const players = await client.players.getByAddresses(['ks0d5iqb6p']);
|
|
59
|
+
console.log('Player:', players[0]?.minecraftName);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### With Authentication
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { KrawletClient } from 'krawlet-js';
|
|
66
|
+
|
|
67
|
+
// Authenticated client (1,000-5,000 requests/hour)
|
|
68
|
+
const client = new KrawletClient({
|
|
69
|
+
apiKey: 'kraw_your_api_key_here',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const shops = await client.shops.getAll();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Configuration
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
const client = new KrawletClient({
|
|
79
|
+
// API base URL (default: 'https://api.krawlet.cc')
|
|
80
|
+
baseUrl: 'https://api.krawlet.cc',
|
|
81
|
+
|
|
82
|
+
// Optional API key for authentication
|
|
83
|
+
apiKey: 'kraw_your_key_here',
|
|
84
|
+
|
|
85
|
+
// Request timeout in milliseconds (default: 30000)
|
|
86
|
+
timeout: 30000,
|
|
87
|
+
|
|
88
|
+
// Custom headers to include in all requests
|
|
89
|
+
headers: {
|
|
90
|
+
'X-Custom-Header': 'value',
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
// Enable automatic retry on failure (default: true)
|
|
94
|
+
enableRetry: true,
|
|
95
|
+
|
|
96
|
+
// Maximum number of retries (default: 3)
|
|
97
|
+
maxRetries: 3,
|
|
98
|
+
|
|
99
|
+
// Initial retry delay in milliseconds (default: 1000)
|
|
100
|
+
retryDelay: 1000,
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Local Development
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
const client = new KrawletClient({
|
|
108
|
+
baseUrl: 'http://localhost:3330/api',
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## API Reference
|
|
113
|
+
|
|
114
|
+
### Health
|
|
115
|
+
|
|
116
|
+
Check API status and health.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// Basic health check
|
|
120
|
+
const health = await client.health.check();
|
|
121
|
+
console.log(health.status); // "ok"
|
|
122
|
+
|
|
123
|
+
// Detailed health check with system metrics
|
|
124
|
+
const detailed = await client.health.detailed();
|
|
125
|
+
console.log(detailed.status); // "healthy" | "degraded"
|
|
126
|
+
console.log(detailed.details.memory);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Players
|
|
130
|
+
|
|
131
|
+
Retrieve player information.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// Get all players
|
|
135
|
+
const allPlayers = await client.players.getAll();
|
|
136
|
+
|
|
137
|
+
// Find by Kromer addresses
|
|
138
|
+
const byAddress = await client.players.getByAddresses(['ks0d5iqb6p', 'k12345678']);
|
|
139
|
+
|
|
140
|
+
// Find by Minecraft names (case-insensitive)
|
|
141
|
+
const byName = await client.players.getByNames(['Twijn', 'Player2']);
|
|
142
|
+
|
|
143
|
+
// Find by Minecraft UUIDs
|
|
144
|
+
const byUuid = await client.players.getByUuids([
|
|
145
|
+
'd98440d6-5117-4ac8-bd50-70b086101e3e',
|
|
146
|
+
]);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Shops
|
|
150
|
+
|
|
151
|
+
Manage shop data and listings.
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
// Get all shops
|
|
155
|
+
const shops = await client.shops.getAll();
|
|
156
|
+
|
|
157
|
+
// Get a specific shop by ID
|
|
158
|
+
const shop = await client.shops.get('123');
|
|
159
|
+
|
|
160
|
+
// Get items for a shop
|
|
161
|
+
const items = await client.shops.getItems('123');
|
|
162
|
+
|
|
163
|
+
// Update a shop (requires ShopSync authentication)
|
|
164
|
+
const shopData = {
|
|
165
|
+
info: {
|
|
166
|
+
name: 'My Shop',
|
|
167
|
+
description: 'A great shop',
|
|
168
|
+
owner: 'PlayerName',
|
|
169
|
+
computerID: 123,
|
|
170
|
+
software: { name: 'ShopSync', version: '1.0.0' },
|
|
171
|
+
location: {
|
|
172
|
+
coordinates: [100, 64, -200],
|
|
173
|
+
description: 'Near spawn',
|
|
174
|
+
dimension: 'overworld',
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
items: [
|
|
178
|
+
{
|
|
179
|
+
item: {
|
|
180
|
+
name: 'minecraft:diamond',
|
|
181
|
+
displayName: 'Diamond',
|
|
182
|
+
},
|
|
183
|
+
stock: 64,
|
|
184
|
+
prices: [{ value: 10, currency: 'KST', address: 'ks0d5iqb6p' }],
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
await client.shops.update(shopData, 'kraw_shopsync_token');
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Items
|
|
193
|
+
|
|
194
|
+
Retrieve item listings across all shops.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// Get all items with prices
|
|
198
|
+
const items = await client.items.getAll();
|
|
199
|
+
|
|
200
|
+
// Filter diamonds
|
|
201
|
+
const diamonds = items.filter(item => item.itemName === 'minecraft:diamond');
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Addresses
|
|
205
|
+
|
|
206
|
+
Get known Kromer addresses.
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
// Get all known addresses
|
|
210
|
+
const addresses = await client.addresses.getAll();
|
|
211
|
+
|
|
212
|
+
// Filter by type
|
|
213
|
+
const shops = addresses.filter(addr => addr.type === 'shop');
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Storage
|
|
217
|
+
|
|
218
|
+
Manage ender storage data (requires authentication).
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
// Get stored data
|
|
222
|
+
const data = await client.storage.get();
|
|
223
|
+
console.log(data.data);
|
|
224
|
+
console.log(data.retrievedAt);
|
|
225
|
+
|
|
226
|
+
// Store new data
|
|
227
|
+
const newData = {
|
|
228
|
+
items: [
|
|
229
|
+
{ name: 'minecraft:diamond', quantity: 64 },
|
|
230
|
+
],
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
await client.storage.set(newData, 'kraw_storage_token');
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Reports
|
|
237
|
+
|
|
238
|
+
Access ShopSync statistics and change logs.
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
// Get overall statistics
|
|
242
|
+
const stats = await client.reports.getStats();
|
|
243
|
+
|
|
244
|
+
// Get shop change logs with filters
|
|
245
|
+
const shopChanges = await client.reports.getShopChangeLogs({
|
|
246
|
+
shopId: '123',
|
|
247
|
+
since: '2026-01-01T00:00:00Z',
|
|
248
|
+
limit: 100,
|
|
249
|
+
offset: 0,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Get item changes
|
|
253
|
+
const itemChanges = await client.reports.getItemChangeLogs({
|
|
254
|
+
shopId: '123',
|
|
255
|
+
limit: 50,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Get price changes
|
|
259
|
+
const priceChanges = await client.reports.getPriceChangeLogs({
|
|
260
|
+
since: '2026-01-15T00:00:00Z',
|
|
261
|
+
until: '2026-01-20T00:00:00Z',
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Get validation failures
|
|
265
|
+
const failures = await client.reports.getValidationFailures({ limit: 10 });
|
|
266
|
+
|
|
267
|
+
// Get successful posts
|
|
268
|
+
const successes = await client.reports.getSuccessfulPosts({ limit: 10 });
|
|
269
|
+
|
|
270
|
+
// Get specific report
|
|
271
|
+
const report = await client.reports.get('report-id');
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Error Handling
|
|
275
|
+
|
|
276
|
+
The library provides a custom `KrawletError` class for API errors.
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import { KrawletError, ErrorCode } from 'krawlet-js';
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
await client.shops.get('nonexistent');
|
|
283
|
+
} catch (error) {
|
|
284
|
+
if (error instanceof KrawletError) {
|
|
285
|
+
console.error('Error code:', error.code);
|
|
286
|
+
console.error('Status code:', error.statusCode);
|
|
287
|
+
console.error('Request ID:', error.requestId);
|
|
288
|
+
console.error('Message:', error.message);
|
|
289
|
+
|
|
290
|
+
// Check error type
|
|
291
|
+
if (error.isClientError()) {
|
|
292
|
+
console.log('Client error (4xx)');
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (error.isServerError()) {
|
|
296
|
+
console.log('Server error (5xx)');
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (error.isRateLimitError()) {
|
|
300
|
+
console.log('Rate limit exceeded');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Check specific error codes
|
|
304
|
+
if (error.code === ErrorCode.SHOP_NOT_FOUND) {
|
|
305
|
+
console.log('Shop does not exist');
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Error Codes
|
|
312
|
+
|
|
313
|
+
Common error codes:
|
|
314
|
+
|
|
315
|
+
- `BAD_REQUEST` - Invalid request
|
|
316
|
+
- `UNAUTHORIZED` - Missing or invalid authentication
|
|
317
|
+
- `FORBIDDEN` - Insufficient permissions
|
|
318
|
+
- `NOT_FOUND` - Resource not found
|
|
319
|
+
- `VALIDATION_ERROR` - Request validation failed
|
|
320
|
+
- `RATE_LIMIT_EXCEEDED` - Too many requests
|
|
321
|
+
- `SHOP_NOT_FOUND` - Shop doesn't exist
|
|
322
|
+
- `PLAYER_NOT_FOUND` - Player doesn't exist
|
|
323
|
+
- `INTERNAL_ERROR` - Server error
|
|
324
|
+
- `DATABASE_ERROR` - Database error
|
|
325
|
+
|
|
326
|
+
## Rate Limiting
|
|
327
|
+
|
|
328
|
+
The API enforces rate limits based on authentication:
|
|
329
|
+
|
|
330
|
+
- **Anonymous**: 100 requests/hour
|
|
331
|
+
- **Free tier**: 1,000 requests/hour
|
|
332
|
+
- **Premium tier**: 5,000 requests/hour
|
|
333
|
+
|
|
334
|
+
Check your current rate limit status:
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
const shops = await client.shops.getAll();
|
|
338
|
+
|
|
339
|
+
const rateLimit = client.getRateLimit();
|
|
340
|
+
if (rateLimit) {
|
|
341
|
+
console.log(`${rateLimit.remaining}/${rateLimit.limit} requests remaining`);
|
|
342
|
+
|
|
343
|
+
const resetDate = new Date(rateLimit.reset * 1000);
|
|
344
|
+
console.log(`Resets at: ${resetDate.toISOString()}`);
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
The client automatically retries requests when rate limits are exceeded with exponential backoff.
|
|
349
|
+
|
|
350
|
+
## TypeScript Support
|
|
351
|
+
|
|
352
|
+
The library is written in TypeScript and provides full type definitions.
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import type { Shop, Item, Player, KrawletError } from 'krawlet-js';
|
|
356
|
+
|
|
357
|
+
// All responses are fully typed
|
|
358
|
+
const shops: Shop[] = await client.shops.getAll();
|
|
359
|
+
const shop: Shop = shops[0];
|
|
360
|
+
const items: Item[] = shop.items;
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## Examples
|
|
364
|
+
|
|
365
|
+
See the [examples](./examples) directory for more usage examples:
|
|
366
|
+
|
|
367
|
+
- [Basic Usage](./examples/usage.ts#basicUsage)
|
|
368
|
+
- [Player Lookup](./examples/usage.ts#playerLookup)
|
|
369
|
+
- [Shop Data](./examples/usage.ts#shopData)
|
|
370
|
+
- [Reports & Analytics](./examples/usage.ts#reports)
|
|
371
|
+
- [Error Handling](./examples/usage.ts#errorHandling)
|
|
372
|
+
- [Custom Configuration](./examples/usage.ts#customConfiguration)
|
|
373
|
+
|
|
374
|
+
## Development
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
# Install dependencies
|
|
378
|
+
pnpm install
|
|
379
|
+
|
|
380
|
+
# Build the library
|
|
381
|
+
pnpm run build
|
|
382
|
+
|
|
383
|
+
# Run tests
|
|
384
|
+
pnpm test
|
|
385
|
+
|
|
386
|
+
# Run tests with coverage
|
|
387
|
+
pnpm run test:coverage
|
|
388
|
+
|
|
389
|
+
# Lint code
|
|
390
|
+
pnpm run lint
|
|
391
|
+
|
|
392
|
+
# Format code
|
|
393
|
+
pnpm run format
|
|
394
|
+
|
|
395
|
+
# Development mode (watch for changes)
|
|
396
|
+
pnpm run dev
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Project Structure
|
|
400
|
+
|
|
401
|
+
```
|
|
402
|
+
krawlet-js/
|
|
403
|
+
├── src/
|
|
404
|
+
│ ├── resources/ # API resource classes
|
|
405
|
+
│ │ ├── health.ts
|
|
406
|
+
│ │ ├── players.ts
|
|
407
|
+
│ │ ├── shops.ts
|
|
408
|
+
│ │ ├── items.ts
|
|
409
|
+
│ │ ├── addresses.ts
|
|
410
|
+
│ │ ├── storage.ts
|
|
411
|
+
│ │ └── reports.ts
|
|
412
|
+
│ ├── __tests__/ # Unit tests
|
|
413
|
+
│ ├── client.ts # Main client class
|
|
414
|
+
│ ├── http-client.ts # HTTP client implementation
|
|
415
|
+
│ ├── error.ts # Error handling
|
|
416
|
+
│ ├── types.ts # TypeScript types
|
|
417
|
+
│ └── index.ts # Main entry point
|
|
418
|
+
├── examples/ # Usage examples
|
|
419
|
+
└── dist/ # Built output
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## License
|
|
423
|
+
|
|
424
|
+
ISC
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Links
|
|
429
|
+
|
|
430
|
+
- **API Documentation**: https://api.krawlet.cc
|
|
431
|
+
- **Production URL**: https://api.krawlet.cc
|
|
432
|
+
- **Local Dev URL**: http://localhost:3330/api
|
|
433
|
+
|
|
434
|
+
## Contributing
|
|
435
|
+
|
|
436
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|