@iteradian-rpc/sdk 1.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 ADDED
@@ -0,0 +1,631 @@
1
+ <p align="center">
2
+ <h1 align="center">Iteradian TypeScript SDK</h1>
3
+ <p align="center">Official TypeScript/JavaScript client library for the Iteradian Control Plane API</p>
4
+ </p>
5
+
6
+ <p align="center">
7
+ <img src="https://img.shields.io/badge/language-TypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" />
8
+ <img src="https://img.shields.io/badge/node-%3E%3D16.0.0-339933?style=flat-square&logo=node.js&logoColor=white" alt="Node 16+" />
9
+ <img src="https://img.shields.io/badge/version-1.0.0-green?style=flat-square" alt="Version" />
10
+ <img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="License" />
11
+ <img src="https://img.shields.io/badge/npm-%40iteradian%2Fsdk-CB3837?style=flat-square&logo=npm&logoColor=white" alt="npm" />
12
+ <img src="https://img.shields.io/badge/deps-zero-brightgreen?style=flat-square" alt="Zero Dependencies" />
13
+ <img src="https://img.shields.io/badge/formats-ESM%20%2B%20CJS-blue?style=flat-square" alt="ESM + CJS" />
14
+ </p>
15
+
16
+ ---
17
+
18
+ ## Features
19
+
20
+ - **Zero runtime dependencies** — uses native `fetch` API only
21
+ - **TypeScript-first** — comprehensive type definitions included (`.d.ts`)
22
+ - **Dual module format** — ships ESM (`.mjs`) and CommonJS (`.js`)
23
+ - **Resource-based API** — clean `client.auth`, `client.organizations`, `client.endpoints` access pattern
24
+ - **Full API coverage** — Auth, Organizations, API Keys, Endpoints, Usage, Dashboard, Alerts, Logs, Subscriptions, Plans, Support
25
+ - **Automatic retry** — exponential backoff on 429 / 5xx responses (configurable)
26
+ - **Timeout support** — via `AbortController` (configurable, default 30s)
27
+ - **Dual auth** — supports both Bearer tokens and `X-API-Key` headers
28
+ - **Tree-shakeable** — individual resource classes can be imported directly
29
+ - **Browser & Node.js** — works anywhere `fetch` is available
30
+
31
+ ## Requirements
32
+
33
+ - **Node.js 16** or later (for native `fetch`)
34
+ - **TypeScript 5.3+** (recommended, for type checking)
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ npm install @iteradian-rpc/sdk
40
+ ```
41
+
42
+ ```bash
43
+ yarn add @iteradian-rpc/sdk
44
+ ```
45
+
46
+ ```bash
47
+ pnpm add @iteradian-rpc/sdk
48
+ ```
49
+
50
+ ## Quick Start
51
+
52
+ ```typescript
53
+ import { IteradianClient } from "@iteradian-rpc/sdk";
54
+
55
+ const client = new IteradianClient({
56
+ baseUrl: "https://api.iteradian.com/api/v1",
57
+ });
58
+
59
+ // Login — sets the access token automatically
60
+ const tokens = await client.auth.login({
61
+ email: "user@example.com",
62
+ password: "password123",
63
+ });
64
+ console.log(`Logged in as ${tokens.user.email}`);
65
+
66
+ // List organizations
67
+ const orgs = await client.organizations.list();
68
+ console.log(`Organizations: ${orgs.length}`);
69
+
70
+ if (orgs.length > 0) {
71
+ const orgId = orgs[0].id;
72
+
73
+ // List endpoints
74
+ const endpoints = await client.endpoints.list(orgId);
75
+ for (const ep of endpoints) {
76
+ console.log(` ${ep.name}: ${ep.status} (${ep.region})`);
77
+ }
78
+
79
+ // Create API key
80
+ const key = await client.apiKeys.create(orgId, {
81
+ name: "Production Key",
82
+ environment: "live",
83
+ });
84
+ console.log(`Created key: ${key.prefix}`);
85
+
86
+ // Query logs
87
+ const logs = await client.logs.query(orgId, {
88
+ status: "error",
89
+ pageSize: 50,
90
+ });
91
+ console.log(`Total logs: ${logs.total}`);
92
+ }
93
+ ```
94
+
95
+ ### JavaScript (CommonJS)
96
+
97
+ ```javascript
98
+ const { IteradianClient } = require("@iteradian-rpc/sdk");
99
+
100
+ const client = new IteradianClient({
101
+ baseUrl: "https://api.iteradian.com/api/v1",
102
+ });
103
+ ```
104
+
105
+ ### Using API Key Authentication
106
+
107
+ ```typescript
108
+ const client = new IteradianClient({
109
+ baseUrl: "https://api.iteradian.com/api/v1",
110
+ apiKey: "itrd_live_abc123...",
111
+ });
112
+
113
+ const endpoints = await client.endpoints.list("org-id");
114
+ ```
115
+
116
+ ### Configuration Options
117
+
118
+ ```typescript
119
+ import { IteradianClient, IteradianConfig } from "@iteradian-rpc/sdk";
120
+
121
+ const config: IteradianConfig = {
122
+ baseUrl: "https://api.iteradian.com/api/v1", // API base URL
123
+ accessToken: "existing-token", // Pre-set Bearer token
124
+ apiKey: "itrd_live_...", // API key for X-API-Key header
125
+ timeout: 60_000, // Request timeout in ms (default: 30000)
126
+ retry: true, // Enable auto-retry (default: true)
127
+ maxRetries: 5, // Max retry attempts (default: 3)
128
+ headers: {
129
+ // Custom headers
130
+ "X-Custom-Header": "value",
131
+ },
132
+ };
133
+
134
+ const client = new IteradianClient(config);
135
+ ```
136
+
137
+ ## API Reference
138
+
139
+ ### Resource Accessors
140
+
141
+ | Resource | Property | Type | Description |
142
+ | ------------- | ---------------------- | ----------------------- | ----------------------------------- |
143
+ | Auth | `client.auth` | `AuthResource` | Authentication & account management |
144
+ | Organizations | `client.organizations` | `OrganizationsResource` | Organization CRUD & members |
145
+ | API Keys | `client.apiKeys` | `ApiKeysResource` | API key management |
146
+ | Endpoints | `client.endpoints` | `EndpointsResource` | Endpoint & network management |
147
+ | Usage | `client.usage` | `UsageResource` | Usage analytics |
148
+ | Dashboard | `client.dashboard` | `DashboardResource` | Dashboard data & health |
149
+ | Alerts | `client.alerts` | `AlertsResource` | Alert management & rules |
150
+ | Logs | `client.logs` | `LogsResource` | Request log querying |
151
+ | Subscriptions | `client.subscriptions` | `SubscriptionsResource` | Subscription & billing |
152
+ | Plans | `client.plans` | `PlansResource` | Plan catalog |
153
+ | Support | `client.support` | `SupportResource` | Support ticket management |
154
+
155
+ ### Client Methods
156
+
157
+ ```typescript
158
+ // Set/clear access token at runtime
159
+ client.setAccessToken("new-token");
160
+ client.clearAccessToken();
161
+ ```
162
+
163
+ ### Authentication (`client.auth`)
164
+
165
+ ```typescript
166
+ // Login (token set automatically)
167
+ const tokens = await client.auth.login({ email: "...", password: "..." });
168
+
169
+ // Register
170
+ const tokens = await client.auth.register({
171
+ email: "...",
172
+ password: "...",
173
+ name: "...",
174
+ });
175
+
176
+ // Refresh token
177
+ const tokens = await client.auth.refresh(refreshToken);
178
+
179
+ // Logout
180
+ await client.auth.logout();
181
+
182
+ // Two-Factor Authentication
183
+ const setup = await client.auth.enable2FA({ password: "..." });
184
+ console.log(`Secret: ${setup.secret}`);
185
+ console.log(`QR Code: ${setup.qrCode}`);
186
+ await client.auth.verify2FA({ code: "123456" });
187
+ await client.auth.disable2FA({ password: "...", code: "123456" });
188
+
189
+ // Magic Link
190
+ await client.auth.sendMagicLink({ email: "user@example.com" });
191
+
192
+ // Password Reset
193
+ await client.auth.forgotPassword({ email: "user@example.com" });
194
+ await client.auth.resetPassword({ token: "...", newPassword: "..." });
195
+ ```
196
+
197
+ ### Organizations (`client.organizations`)
198
+
199
+ ```typescript
200
+ // CRUD
201
+ const orgs = await client.organizations.list();
202
+ const org = await client.organizations.create({
203
+ name: "My Org",
204
+ slug: "my-org",
205
+ });
206
+ const org = await client.organizations.get(orgId);
207
+ await client.organizations.delete(orgId);
208
+
209
+ // Members
210
+ const members = await client.organizations.listMembers(orgId);
211
+ const member = await client.organizations.inviteMember(orgId, {
212
+ email: "user@example.com",
213
+ role: "member",
214
+ });
215
+ await client.organizations.removeMember(orgId, memberId);
216
+ ```
217
+
218
+ ### API Keys (`client.apiKeys`)
219
+
220
+ ```typescript
221
+ const keys = await client.apiKeys.list(orgId);
222
+ const key = await client.apiKeys.create(orgId, {
223
+ name: "Key Name",
224
+ environment: "live",
225
+ });
226
+ await client.apiKeys.revoke(orgId, keyId);
227
+ const newKey = await client.apiKeys.rotate(orgId, keyId);
228
+ const analytics = await client.apiKeys.getAnalytics(orgId, keyId);
229
+ ```
230
+
231
+ ### Endpoints (`client.endpoints`)
232
+
233
+ ```typescript
234
+ // Networks
235
+ const networks = await client.endpoints.getNetworks();
236
+
237
+ // Endpoint management
238
+ const endpoints = await client.endpoints.list(orgId);
239
+ const endpoint = await client.endpoints.create(orgId, {
240
+ name: "...",
241
+ networkId: "...",
242
+ region: "us-east-1",
243
+ });
244
+ await client.endpoints.delete(orgId, endpointId);
245
+ const paused = await client.endpoints.pause(orgId, endpointId);
246
+ const resumed = await client.endpoints.resume(orgId, endpointId);
247
+ const health = await client.endpoints.checkHealth(orgId, endpointId);
248
+ const metrics = await client.endpoints.getMetrics(orgId, endpointId);
249
+ ```
250
+
251
+ ### Usage & Dashboard
252
+
253
+ ```typescript
254
+ // Usage
255
+ const usage = await client.usage.get(orgId, {
256
+ from: "2024-01-01",
257
+ to: "2024-01-31",
258
+ });
259
+
260
+ // Dashboard
261
+ const data = await client.dashboard.get(orgId, { period: "7d" });
262
+ const health = await client.dashboard.getHealth(orgId);
263
+ const stats = await client.dashboard.getQuickStats(orgId, { period: "24h" });
264
+ ```
265
+
266
+ ### Alerts (`client.alerts`)
267
+
268
+ ```typescript
269
+ // Alerts
270
+ const alerts = await client.alerts.list(orgId);
271
+ const ack = await client.alerts.acknowledge(orgId, alertId);
272
+ const resolved = await client.alerts.resolve(orgId, alertId);
273
+
274
+ // Alert Rules
275
+ const rules = await client.alerts.listRules(orgId);
276
+ const rule = await client.alerts.createRule(orgId, {
277
+ name: "High Latency",
278
+ metric: "latency_p95",
279
+ condition: "greater_than",
280
+ threshold: 500,
281
+ severity: "warning",
282
+ isEnabled: true,
283
+ cooldownMinutes: 15,
284
+ });
285
+ await client.alerts.deleteRule(orgId, ruleId);
286
+
287
+ // Channels
288
+ const channels = await client.alerts.getChannels(orgId);
289
+ await client.alerts.testChannel(orgId, channelId);
290
+ ```
291
+
292
+ ### Logs (`client.logs`)
293
+
294
+ ```typescript
295
+ // Query with filters
296
+ const logs = await client.logs.query(orgId, {
297
+ page: 1,
298
+ pageSize: 50,
299
+ status: "error",
300
+ method: "eth_call",
301
+ network: "ethereum",
302
+ sortBy: "timestamp",
303
+ sortOrder: "desc",
304
+ });
305
+ console.log(`Page ${logs.page}/${logs.totalPages}`);
306
+ for (const log of logs.logs) {
307
+ console.log(` [${log.status}] ${log.method} (${log.latencyMs}ms)`);
308
+ }
309
+
310
+ // Get single log
311
+ const log = await client.logs.get(orgId, logId);
312
+
313
+ // Filter options
314
+ const filters = await client.logs.getFilterOptions(orgId);
315
+
316
+ // Stats
317
+ const stats = await client.logs.getStats(orgId, { period: "24h" });
318
+ ```
319
+
320
+ ### Subscriptions (`client.subscriptions`)
321
+
322
+ ```typescript
323
+ const sub = await client.subscriptions.get(orgId);
324
+ const updated = await client.subscriptions.changePlan(orgId, { planId: "pro" });
325
+ const cancelled = await client.subscriptions.cancel(orgId);
326
+ const reactivated = await client.subscriptions.reactivate(orgId);
327
+ const invoices = await client.subscriptions.getInvoices(orgId);
328
+ ```
329
+
330
+ ### Plans (`client.plans`)
331
+
332
+ ```typescript
333
+ const plans = await client.plans.list();
334
+ const plan = await client.plans.get(planId);
335
+ ```
336
+
337
+ ### Support (`client.support`)
338
+
339
+ ```typescript
340
+ const tickets = await client.support.listTickets(orgId);
341
+ const ticket = await client.support.createTicket(orgId, {
342
+ subject: "API returning 500 errors",
343
+ category: "technical",
344
+ priority: "high",
345
+ message: "Detailed description...",
346
+ });
347
+ const detail = await client.support.getTicket(orgId, ticketId);
348
+ await client.support.addMessage(orgId, ticketId, {
349
+ content: "Follow-up message...",
350
+ });
351
+ ```
352
+
353
+ ## Type Definitions
354
+
355
+ All types are exported from the package and defined in `src/types.ts` (538 lines):
356
+
357
+ ### Configuration
358
+
359
+ | Type | Fields |
360
+ | ----------------- | -------------------------------------------------------------------------------------- |
361
+ | `IteradianConfig` | `baseUrl?`, `accessToken?`, `apiKey?`, `timeout?`, `retry?`, `maxRetries?`, `headers?` |
362
+
363
+ ### Auth Types
364
+
365
+ | Type | Fields |
366
+ | ----------------- | ------------------------------------- |
367
+ | `LoginRequest` | `email`, `password`, `twoFactorCode?` |
368
+ | `RegisterRequest` | `email`, `password`, `name` |
369
+ | `AuthTokens` | `accessToken`, `refreshToken`, `user` |
370
+ | `TwoFASetup` | `secret`, `qrCode` |
371
+
372
+ ### Organization Types
373
+
374
+ | Type | Fields |
375
+ | --------------------- | ---------------------------------------------- |
376
+ | `Organization` | `id`, `name`, `slug`, `createdAt`, `updatedAt` |
377
+ | `OrgMember` | `id`, `userId`, `email`, `role`, `joinedAt` |
378
+ | `CreateOrgRequest` | `name`, `slug` |
379
+ | `InviteMemberRequest` | `email`, `role` |
380
+
381
+ ### API Key Types
382
+
383
+ | Type | Fields |
384
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
385
+ | `ApiKey` | `id`, `name`, `prefix`, `key?`, `environment`, `status`, `ipAllowlist?`, `allowedNetworks?`, `rateLimit?`, `dailyLimit?`, `createdAt`, `updatedAt`, `expiresAt?`, `lastUsedAt?` |
386
+ | `CreateApiKeyRequest` | `name`, `environment`, `ipAllowlist?`, `allowedNetworks?`, `rateLimit?`, `dailyLimit?`, `expiresAt?` |
387
+
388
+ ### Network & Endpoint Types
389
+
390
+ | Type | Fields |
391
+ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
392
+ | `Network` | `id`, `slug`, `name`, `chainId`, `type`, `environment`, `isActive` |
393
+ | `Endpoint` | `id`, `organizationId`, `networkId`, `region`, `name`, `priority`, `status`, `isEnabled`, `timeoutMs`, `retryCount`, metrics |
394
+ | `CreateEndpointRequest` | `name`, `networkId`, `region`, `priority?`, `timeoutMs?`, `retryCount?` |
395
+
396
+ ### Logging Types
397
+
398
+ | Type | Fields |
399
+ | ---------------- | ----------------------------------------------------------------------------------------------------------- |
400
+ | `RequestLog` | `id`, `organizationId`, `method`, `status`, `statusCode?`, `latencyMs?`, `network?`, `region?`, `timestamp` |
401
+ | `LogsResponse` | `logs`, `total`, `page`, `pageSize`, `totalPages` |
402
+ | `LogQueryParams` | `page?`, `pageSize?`, `status?`, `method?`, `network?`, `region?`, `from?`, `to?`, `sortBy?`, `sortOrder?` |
403
+
404
+ ### Alert Types
405
+
406
+ | Type | Fields |
407
+ | ------------------------ | -------------------------------------------------------------------------------------------------------------- |
408
+ | `Alert` | `id`, `organizationId`, `ruleId?`, `severity`, `status`, `title`, `message`, `metadata?` |
409
+ | `AlertRule` | `id`, `organizationId`, `name`, `metric`, `condition`, `threshold`, `severity`, `isEnabled`, `cooldownMinutes` |
410
+ | `CreateAlertRuleRequest` | `name`, `metric`, `condition`, `threshold`, `severity`, `isEnabled`, `cooldownMinutes` |
411
+
412
+ ### Billing Types
413
+
414
+ | Type | Fields |
415
+ | -------------- | --------------------------------------------------------------------------------------- |
416
+ | `Plan` | `id`, `name`, `slug`, `price`, `currency`, `interval`, `features`, `limits`, `isActive` |
417
+ | `Subscription` | `id`, `organizationId`, `planId`, `status`, `cancelAtPeriodEnd`, `plan?` |
418
+
419
+ ### Support Types
420
+
421
+ | Type | Fields |
422
+ | --------------------- | ------------------------------------------------------------------- |
423
+ | `SupportTicket` | `id`, `organizationId`, `subject`, `category`, `priority`, `status` |
424
+ | `CreateTicketRequest` | `subject`, `category`, `priority`, `message` |
425
+
426
+ ### Error Types
427
+
428
+ | Type | Fields |
429
+ | ---------- | --------------------------------- |
430
+ | `ApiError` | `message`, `statusCode`, `error?` |
431
+
432
+ ## Error Handling
433
+
434
+ ```typescript
435
+ import { IteradianClient, IteradianError } from "@iteradian-rpc/sdk";
436
+
437
+ const client = new IteradianClient({ baseUrl: "..." });
438
+
439
+ try {
440
+ await client.auth.login({ email: "user@example.com", password: "wrong" });
441
+ } catch (err) {
442
+ if (err instanceof IteradianError) {
443
+ console.log(`Status: ${err.statusCode}`); // 401
444
+ console.log(`Message: ${err.message}`); // "Invalid credentials"
445
+ console.log(`Error: ${err.error}`); // Error code
446
+ } else {
447
+ console.log(`Unexpected error: ${err}`);
448
+ }
449
+ }
450
+ ```
451
+
452
+ On a gateway call the same error also carries the JSON-RPC detail, which is how
453
+ you tell "wait a second" from "you are out of quota until the period rolls
454
+ over":
455
+
456
+ ```typescript
457
+ try {
458
+ await client.rpc.call("tao-mainnet", {
459
+ jsonrpc: "2.0",
460
+ method: "system_health",
461
+ params: [],
462
+ id: 1,
463
+ });
464
+ } catch (err) {
465
+ if (err instanceof IteradianError) {
466
+ if (err.isRateLimited) {
467
+ // -32005. Wait err.retryAfter seconds and try again.
468
+ } else if (err.isQuotaExhausted) {
469
+ // -32006 or -32007. Retrying will not help: err.data.resetsAt says when
470
+ // the allowance returns, and the cap needs a plan change.
471
+ }
472
+ }
473
+ }
474
+ ```
475
+
476
+ Pass an `AbortSignal` to cancel a call:
477
+
478
+ ```typescript
479
+ const controller = new AbortController();
480
+ setTimeout(() => controller.abort(), 1000);
481
+
482
+ await client.rpc.call("tao-mainnet", request, { signal: controller.signal });
483
+ ```
484
+
485
+ ### Retry Behavior
486
+
487
+ The SDK automatically retries:
488
+
489
+ - **5xx Server Errors** — with exponential backoff
490
+ - **429 Too Many Requests**, but **only** `-32005` (rate or concurrency limit).
491
+ `-32006` (monthly quota exhausted) and `-32007` (overage spend cap) do not
492
+ recover until the billing period rolls over, so retrying them burns your time
493
+ for a guaranteed 429.
494
+
495
+ Backoff formula: `min(1000 * 2^(attempt-1), 10000)` ms, or the gateway's own
496
+ `retryAfter` hint when it gives one — capped at 30 seconds either way.
497
+
498
+ **Transaction submissions are never retried.** A request whose JSON-RPC method
499
+ submits a transaction (`eth_sendRawTransaction`, `author_submitExtrinsic`,
500
+ `sendTransaction`, and the rest) is sent exactly once: a timeout says nothing
501
+ about whether the node already accepted and gossiped it, and a retry could
502
+ double-submit. The gateway applies the same rule when failing over between
503
+ nodes.
504
+
505
+ **Redirects are not followed.** Neither host redirects, and following one would
506
+ resend your API key to whatever origin the redirect named. A 3xx raises
507
+ `IteradianError` with `error: "UNEXPECTED_REDIRECT"`.
508
+
509
+ Configure via constructor:
510
+
511
+ ```typescript
512
+ const client = new IteradianClient({
513
+ baseUrl: "...",
514
+ retry: true, // Enable retry (default: true)
515
+ maxRetries: 5, // Max retry attempts (default: 3)
516
+ timeout: 60_000, // Timeout per request (default: 30000ms)
517
+ });
518
+ ```
519
+
520
+ To disable retries:
521
+
522
+ ```typescript
523
+ const client = new IteradianClient({
524
+ baseUrl: "...",
525
+ retry: false,
526
+ });
527
+ ```
528
+
529
+ ## Advanced Usage
530
+
531
+ ### Importing Individual Resources
532
+
533
+ For tree-shaking or advanced use cases, you can import resource classes directly:
534
+
535
+ ```typescript
536
+ import { AuthResource } from "@iteradian-rpc/sdk";
537
+ import { HttpClient } from "@iteradian-rpc/sdk/http";
538
+
539
+ const http = new HttpClient({ baseUrl: "..." });
540
+ const auth = new AuthResource(http);
541
+ const tokens = await auth.login({ email: "...", password: "..." });
542
+ ```
543
+
544
+ ### Pre-Authenticated Client
545
+
546
+ ```typescript
547
+ const client = new IteradianClient({
548
+ baseUrl: "https://api.iteradian.com/api/v1",
549
+ accessToken: "existing-jwt-token",
550
+ });
551
+
552
+ // No login needed — use the API directly
553
+ const orgs = await client.organizations.list();
554
+ ```
555
+
556
+ ## Build & Development
557
+
558
+ ```bash
559
+ # Build (CJS + ESM + DTS)
560
+ npm run build
561
+
562
+ # Watch mode
563
+ npm run dev
564
+
565
+ # Type check
566
+ npm run lint
567
+
568
+ # Test
569
+ npm run test
570
+ ```
571
+
572
+ Built with [tsup](https://github.com/egoist/tsup) — outputs:
573
+
574
+ - `dist/index.js` (CommonJS)
575
+ - `dist/index.mjs` (ESM)
576
+ - `dist/index.d.ts` (TypeScript declarations)
577
+
578
+ ## Project Structure
579
+
580
+ ```
581
+ sdks/typescript/
582
+ ├── package.json # @iteradian-rpc/sdk, zero runtime deps
583
+ ├── tsconfig.json # TypeScript config (ES2020, strict)
584
+ ├── README.md # This file
585
+ └── src/
586
+ ├── index.ts # Re-exports everything
587
+ ├── client.ts # IteradianClient class (110 lines)
588
+ ├── http.ts # HttpClient + IteradianError (155 lines)
589
+ ├── types.ts # All TypeScript interfaces (538 lines)
590
+ └── resources/
591
+ ├── auth.ts # AuthResource
592
+ ├── organizations.ts
593
+ ├── api-keys.ts # ApiKeysResource
594
+ ├── endpoints.ts # EndpointsResource
595
+ ├── usage.ts # UsageResource
596
+ ├── dashboard.ts # DashboardResource
597
+ ├── alerts.ts # AlertsResource
598
+ ├── logs.ts # LogsResource
599
+ ├── subscriptions.ts
600
+ ├── plans.ts # PlansResource
601
+ └── support.ts # SupportResource
602
+ ```
603
+
604
+ ## License
605
+
606
+ MIT © [Iteradian](https://iteradian.com)
607
+
608
+ ## RPC gateway, rate limits and quotas
609
+
610
+ The RPC gateway is a **different host** from the control-plane API:
611
+
612
+ | Surface | Base URL |
613
+ | --- | --- |
614
+ | Control plane | `https://api.iteradian.com/api/v1` |
615
+ | RPC gateway | `https://rpc.iteradian.com` |
616
+
617
+ This SDK takes both, and defaults the gateway to `https://rpc.iteradian.com`.
618
+
619
+ - A **batch of N calls costs N** against your per-second rate limit and your
620
+ monthly quota. Batching saves round trips, not allowance.
621
+ - Limits are **per subscription**, aggregated over every API key your
622
+ organization holds. Creating more keys does not raise them.
623
+ - The gateway returns HTTP 429 with a JSON-RPC error body:
624
+ `-32005` rate limited (retry after `error.data.retryAfter`), `-32006` monthly
625
+ quota exhausted, `-32007` overage spend cap reached. The last two do not
626
+ recover until the billing period rolls over, so retrying them is wasted work.
627
+
628
+ Plans: Developer 20 rps / 5M per month, Professional 100 rps / 30M, Dedicated
629
+ per contract. See `sdks/SDK_CONTRACT.md` for the full table.
630
+
631
+ **WebSocket is not available.** The gateway serves HTTPS JSON-RPC only.