@iteradian-rpc/sdk 1.0.1 → 1.2.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/dist/index.js CHANGED
@@ -48,9 +48,21 @@ var IteradianError = class extends Error {
48
48
  this.retryAfter = rpc?.retryAfter;
49
49
  this.data = rpc?.data;
50
50
  }
51
- /** True when the request failed because the subscription is out of allowance. */
51
+ /**
52
+ * True when the request failed because an allowance is used up and retrying
53
+ * will not help until it resets: the subscription quota (-32006), the
54
+ * overage spend cap (-32007) or the API key's daily limit (-32008).
55
+ */
52
56
  get isQuotaExhausted() {
53
- return this.rpcCode === -32006 || this.rpcCode === -32007;
57
+ return this.rpcCode === -32006 || this.rpcCode === -32007 || this.rpcCode === -32008;
58
+ }
59
+ /**
60
+ * True when the API key's own daily limit is reached (-32008). `data` then
61
+ * carries `{ dailyLimit, used, cost, resetsAt }`; `resetsAt` is the next
62
+ * 00:00 UTC.
63
+ */
64
+ get isDailyLimitReached() {
65
+ return this.rpcCode === -32008;
54
66
  }
55
67
  /** True when the request was throttled and is worth retrying. */
56
68
  get isRateLimited() {
@@ -140,7 +152,11 @@ var HttpClient = class {
140
152
  if (!response.ok) {
141
153
  let errorBody;
142
154
  try {
143
- errorBody = await response.json();
155
+ const parsed = await response.json();
156
+ if (parsed === null || typeof parsed !== "object") {
157
+ throw new Error("error body is not an object");
158
+ }
159
+ errorBody = parsed;
144
160
  } catch {
145
161
  errorBody = {
146
162
  message: response.statusText || "Unknown error",
@@ -150,7 +166,7 @@ var HttpClient = class {
150
166
  const rpc = errorBody?.error;
151
167
  const rpcCode = typeof rpc?.code === "number" ? rpc.code : void 0;
152
168
  const retryAfter = typeof rpc?.data?.retryAfter === "number" ? rpc.data.retryAfter : void 0;
153
- const worthRetrying = response.status >= 500 || response.status === 429 && rpcCode !== -32006 && rpcCode !== -32007;
169
+ const worthRetrying = response.status >= 500 || response.status === 429 && rpcCode !== -32006 && rpcCode !== -32007 && rpcCode !== -32008;
154
170
  if (this.retry && attempt < this.maxRetries && worthRetrying && isReplayableBody(body) && !controller.signal.aborted) {
155
171
  const backoff = Math.min(1e3 * 2 ** (attempt - 1), 1e4);
156
172
  const delay = Math.min(
@@ -160,10 +176,14 @@ var HttpClient = class {
160
176
  await new Promise((r) => setTimeout(r, delay));
161
177
  return this.request(method, path, body, attempt + 1, base, signal);
162
178
  }
179
+ const rawMessage = errorBody.message;
180
+ const bodyMessage = Array.isArray(rawMessage) ? rawMessage.map(String).join(", ") : typeof rawMessage === "string" ? rawMessage : "";
181
+ const rpcMessage = typeof rpc?.message === "string" ? rpc.message : "";
182
+ const errorLabel = errorBody.error;
163
183
  throw new IteradianError(
164
- rpc?.message || errorBody.message || response.statusText,
165
- errorBody.statusCode || response.status,
166
- errorBody.error,
184
+ rpcMessage || bodyMessage || response.statusText || `HTTP ${response.status}`,
185
+ typeof errorBody.statusCode === "number" ? errorBody.statusCode : response.status,
186
+ typeof errorLabel === "string" ? errorLabel : void 0,
167
187
  { code: rpcCode, retryAfter, data: rpc?.data }
168
188
  );
169
189
  }
@@ -236,15 +256,40 @@ var AuthResource = class {
236
256
  constructor(http) {
237
257
  this.http = http;
238
258
  }
239
- /** Register a new user account */
259
+ /**
260
+ * Register a new user account. Does not sign in: the API answers
261
+ * `{ message, email }` (the same for an address that already has an
262
+ * account) and emails a confirmation link. Call `login()` once the address
263
+ * is confirmed.
264
+ *
265
+ * The server rejects registration (400) unless the user agreed to the
266
+ * Terms of Service, Privacy Policy and DPA, so `data.acceptedTerms` is
267
+ * required and always sent. Pass `acceptedTerms: true` only after the user
268
+ * has ticked the agreement.
269
+ */
240
270
  register(data) {
241
- return this.http.post("/auth/register", data);
271
+ return this.http.post("/auth/register", {
272
+ ...data,
273
+ acceptedTerms: data?.acceptedTerms === true
274
+ });
242
275
  }
243
- /** Login with email/password (optionally with 2FA code) */
276
+ /**
277
+ * Login with email/password (optionally with a 2FA code or a backup code).
278
+ *
279
+ * When two-factor auth is on and no code was sent, the API answers
280
+ * `{ requires2FA: true }` with no tokens. Check `requires2FA` and call
281
+ * again with `twoFactorCode` or `backupCode`. The stored access token is
282
+ * only replaced when the answer carries one.
283
+ */
244
284
  async login(data) {
245
- const tokens = await this.http.post("/auth/login", data);
246
- this.http.setAccessToken(tokens.accessToken);
247
- return tokens;
285
+ const result = await this.http.post("/auth/login", data);
286
+ this.storeToken(result);
287
+ return result;
288
+ }
289
+ storeToken(result) {
290
+ if (result && typeof result.accessToken === "string" && result.accessToken) {
291
+ this.http.setAccessToken(result.accessToken);
292
+ }
248
293
  }
249
294
  /** Logout current session */
250
295
  logout() {
@@ -255,7 +300,7 @@ var AuthResource = class {
255
300
  const tokens = await this.http.post("/auth/refresh", {
256
301
  refreshToken
257
302
  });
258
- this.http.setAccessToken(tokens.accessToken);
303
+ this.storeToken(tokens);
259
304
  return tokens;
260
305
  }
261
306
  /** Verify email with token */
@@ -280,11 +325,11 @@ var AuthResource = class {
280
325
  }
281
326
  /** Login via magic link token */
282
327
  async loginWithMagicLink(token) {
283
- const tokens = await this.http.post("/auth/magic-login", {
328
+ const result = await this.http.post("/auth/magic-login", {
284
329
  token
285
330
  });
286
- this.http.setAccessToken(tokens.accessToken);
287
- return tokens;
331
+ this.storeToken(result);
332
+ return result;
288
333
  }
289
334
  /** Enable 2FA – returns QR code image and secret */
290
335
  enable2FA(password) {
@@ -313,7 +358,11 @@ var OrganizationsResource = class {
313
358
  list() {
314
359
  return this.http.get("/orgs");
315
360
  }
316
- /** Create a new organization */
361
+ /**
362
+ * Create a new organization. `name`, `planId` and `acceptedTerms` are
363
+ * required by the API; pass `acceptedTerms: true` only after the user
364
+ * agreed to the terms.
365
+ */
317
366
  create(data) {
318
367
  return this.http.post("/orgs", data);
319
368
  }
@@ -337,10 +386,47 @@ var OrganizationsResource = class {
337
386
  listMembers(orgId) {
338
387
  return this.http.get(`/orgs/${orgId}/members`);
339
388
  }
340
- /** Invite a member to the organization */
389
+ /**
390
+ * Invite someone to the organization by email. Creates (or refreshes) a
391
+ * pending invitation — nobody becomes a member until the invitee accepts
392
+ * it while signed in with a verified address.
393
+ */
341
394
  inviteMember(orgId, data) {
342
395
  return this.http.post(`/orgs/${orgId}/members`, data);
343
396
  }
397
+ /** Open invitations of the organization (owner/admin) */
398
+ listInvites(orgId) {
399
+ return this.http.get(`/orgs/${orgId}/invites`);
400
+ }
401
+ /** Revoke an open invitation (owner/admin) */
402
+ revokeInvite(orgId, inviteId) {
403
+ return this.http.delete(`/orgs/${orgId}/invites/${inviteId}`);
404
+ }
405
+ /** Invitations addressed to the signed-in user */
406
+ listMyInvites() {
407
+ return this.http.get("/invites");
408
+ }
409
+ /**
410
+ * Accept an invitation addressed to the signed-in user.
411
+ *
412
+ * If the user has not accepted the current terms version yet, the API
413
+ * answers 403 (`TERMS_ACCEPTANCE_REQUIRED`) unless
414
+ * `{ acceptedTerms: true }` is passed — only after the user agreed to the
415
+ * Terms of Service, Privacy Policy and DPA. `acceptedTerms` is sent only
416
+ * when given.
417
+ */
418
+ acceptInvite(inviteId, options) {
419
+ if (options?.acceptedTerms !== void 0) {
420
+ return this.http.post(`/invites/${inviteId}/accept`, {
421
+ acceptedTerms: options.acceptedTerms === true
422
+ });
423
+ }
424
+ return this.http.post(`/invites/${inviteId}/accept`);
425
+ }
426
+ /** Decline an invitation addressed to the signed-in user */
427
+ declineInvite(inviteId) {
428
+ return this.http.post(`/invites/${inviteId}/decline`);
429
+ }
344
430
  /** Update a member's role */
345
431
  updateMemberRole(orgId, memberId, role) {
346
432
  return this.http.put(`/orgs/${orgId}/members/${memberId}`, { role });
@@ -356,6 +442,12 @@ var OrganizationsResource = class {
356
442
  };
357
443
 
358
444
  // src/resources/api-keys.ts
445
+ function withKeyAlias(k) {
446
+ if (k && typeof k === "object" && typeof k.secret === "string") {
447
+ k.key = k.secret;
448
+ }
449
+ return k;
450
+ }
359
451
  var ApiKeysResource = class {
360
452
  constructor(http) {
361
453
  this.http = http;
@@ -368,9 +460,16 @@ var ApiKeysResource = class {
368
460
  get(orgId, keyId) {
369
461
  return this.http.get(`/orgs/${orgId}/keys/${keyId}`);
370
462
  }
371
- /** Create a new API key (returns the full key only once) */
372
- create(orgId, data) {
373
- return this.http.post(`/orgs/${orgId}/keys`, data);
463
+ /**
464
+ * Create a new API key. The full key comes back once, in `secret`
465
+ * (`key` is a deprecated alias with the same value).
466
+ */
467
+ async create(orgId, data) {
468
+ const created = await this.http.post(
469
+ `/orgs/${orgId}/keys`,
470
+ data
471
+ );
472
+ return withKeyAlias(created);
374
473
  }
375
474
  /** Update an API key */
376
475
  update(orgId, keyId, data) {
@@ -380,9 +479,15 @@ var ApiKeysResource = class {
380
479
  revoke(orgId, keyId) {
381
480
  return this.http.delete(`/orgs/${orgId}/keys/${keyId}`);
382
481
  }
383
- /** Rotate an API key (revoke old, create new) */
384
- rotate(orgId, keyId) {
385
- return this.http.post(`/orgs/${orgId}/keys/${keyId}/rotate`);
482
+ /**
483
+ * Rotate an API key (revoke old, create new). The new full key is in
484
+ * `secret`; `key` is a deprecated alias.
485
+ */
486
+ async rotate(orgId, keyId) {
487
+ const rotated = await this.http.post(
488
+ `/orgs/${orgId}/keys/${keyId}/rotate`
489
+ );
490
+ return withKeyAlias(rotated);
386
491
  }
387
492
  /** Get analytics for an API key */
388
493
  getAnalytics(orgId, keyId, timeRange = "7d") {
@@ -437,12 +542,16 @@ var EndpointsResource = class {
437
542
  return this.http.post(`/orgs/${orgId}/endpoints/${endpointId}/resume`);
438
543
  }
439
544
  // ==================== Health & Metrics ====================
440
- /** Trigger a health check */
545
+ /** Trigger a health check (POST .../health-check) */
441
546
  checkHealth(orgId, endpointId) {
442
547
  return this.http.post(
443
548
  `/orgs/${orgId}/endpoints/${endpointId}/health-check`
444
549
  );
445
550
  }
551
+ /** Get the current health of an endpoint (GET .../health) */
552
+ getHealth(orgId, endpointId) {
553
+ return this.http.get(`/orgs/${orgId}/endpoints/${endpointId}/health`);
554
+ }
446
555
  /** Get endpoint health summary */
447
556
  getHealthOverview(orgId) {
448
557
  return this.http.get(`/orgs/${orgId}/endpoints/summary`);
@@ -452,8 +561,9 @@ var EndpointsResource = class {
452
561
  const params = new URLSearchParams();
453
562
  if (from) params.append("from", from);
454
563
  if (to) params.append("to", to);
564
+ const qs = params.toString();
455
565
  return this.http.get(
456
- `/orgs/${orgId}/endpoints/${endpointId}/metrics?${params.toString()}`
566
+ `/orgs/${orgId}/endpoints/${endpointId}/metrics${qs ? `?${qs}` : ""}`
457
567
  );
458
568
  }
459
569
  /** Update endpoint priorities */
@@ -469,9 +579,13 @@ var UsageResource = class {
469
579
  constructor(http) {
470
580
  this.http = http;
471
581
  }
472
- /** Get usage analytics for a date range */
582
+ /**
583
+ * Get usage rows (one per key per day) for a date range. `from` and `to`
584
+ * are ISO dates, e.g. `2026-01-31`.
585
+ */
473
586
  get(orgId, from, to) {
474
- return this.http.get(`/orgs/${orgId}/usage?from=${from}&to=${to}`);
587
+ const qs = new URLSearchParams({ from, to }).toString();
588
+ return this.http.get(`/orgs/${orgId}/usage?${qs}`);
475
589
  }
476
590
  /** Get usage summary */
477
591
  getSummary(orgId) {
@@ -480,13 +594,27 @@ var UsageResource = class {
480
594
  };
481
595
 
482
596
  // src/resources/dashboard.ts
597
+ var TIME_RANGES = {
598
+ "1h": "last_hour",
599
+ "24h": "last_24_hours",
600
+ "7d": "last_7_days",
601
+ "30d": "last_30_days"
602
+ };
603
+ function rangeQuery(timeRange, custom) {
604
+ const qs = new URLSearchParams();
605
+ if (timeRange) qs.set("timeRange", TIME_RANGES[timeRange] ?? timeRange);
606
+ if (custom?.from) qs.set("from", custom.from);
607
+ if (custom?.to) qs.set("to", custom.to);
608
+ const s = qs.toString();
609
+ return s ? `?${s}` : "";
610
+ }
483
611
  var DashboardResource = class {
484
612
  constructor(http) {
485
613
  this.http = http;
486
614
  }
487
615
  /** Get full dashboard data */
488
- get(orgId, period) {
489
- const params = period ? `?period=${period}` : "";
616
+ get(orgId, timeRange, custom) {
617
+ const params = rangeQuery(timeRange, custom);
490
618
  return this.http.get(`/orgs/${orgId}/dashboard${params}`);
491
619
  }
492
620
  /** Get system health overview */
@@ -494,23 +622,23 @@ var DashboardResource = class {
494
622
  return this.http.get(`/orgs/${orgId}/dashboard/health`);
495
623
  }
496
624
  /** Get quick stats */
497
- getQuickStats(orgId, period) {
498
- const params = period ? `?period=${period}` : "";
625
+ getQuickStats(orgId, timeRange, custom) {
626
+ const params = rangeQuery(timeRange, custom);
499
627
  return this.http.get(`/orgs/${orgId}/dashboard/quick-stats${params}`);
500
628
  }
501
629
  /** Get request rate time series */
502
- getRequestRate(orgId, period) {
503
- const params = period ? `?period=${period}` : "";
630
+ getRequestRate(orgId, timeRange, custom) {
631
+ const params = rangeQuery(timeRange, custom);
504
632
  return this.http.get(`/orgs/${orgId}/dashboard/request-rate${params}`);
505
633
  }
506
634
  /** Get error rate time series */
507
- getErrorRate(orgId, period) {
508
- const params = period ? `?period=${period}` : "";
635
+ getErrorRate(orgId, timeRange, custom) {
636
+ const params = rangeQuery(timeRange, custom);
509
637
  return this.http.get(`/orgs/${orgId}/dashboard/error-rate${params}`);
510
638
  }
511
639
  /** Get latency metrics */
512
- getLatency(orgId, period) {
513
- const params = period ? `?period=${period}` : "";
640
+ getLatency(orgId, timeRange, custom) {
641
+ const params = rangeQuery(timeRange, custom);
514
642
  return this.http.get(`/orgs/${orgId}/dashboard/latency${params}`);
515
643
  }
516
644
  /** Get performance metrics */
@@ -525,8 +653,17 @@ var AlertsResource = class {
525
653
  this.http = http;
526
654
  }
527
655
  // ==================== Alerts ====================
528
- /** List alerts for an organization */
529
- list(orgId) {
656
+ /**
657
+ * List alerts for an organization. The API answers an overview object
658
+ * (`alerts`, counters, rules, channels); this returns just the alerts.
659
+ * Use `overview()` for the rest.
660
+ */
661
+ async list(orgId) {
662
+ const overview = await this.overview(orgId);
663
+ return Array.isArray(overview?.alerts) ? overview.alerts : [];
664
+ }
665
+ /** The full alerts overview: alerts, counters, rules and channels. */
666
+ overview(orgId) {
530
667
  return this.http.get(`/orgs/${orgId}/alerts`);
531
668
  }
532
669
  /** Acknowledge an alert */
@@ -602,7 +739,7 @@ var LogsResource = class {
602
739
  constructor(http) {
603
740
  this.http = http;
604
741
  }
605
- /** Query request logs with filters and pagination */
742
+ /** Query request logs with filters (`limit` / `offset` paginate) */
606
743
  query(orgId, params) {
607
744
  const searchParams = new URLSearchParams();
608
745
  if (params) {
@@ -638,9 +775,19 @@ var SubscriptionsResource = class {
638
775
  get(orgId) {
639
776
  return this.http.get(`/orgs/${orgId}/subscription`);
640
777
  }
641
- /** Change subscription plan */
642
- changePlan(orgId, planId) {
643
- return this.http.put(`/orgs/${orgId}/subscription/plan`, { planId });
778
+ /**
779
+ * Change subscription plan.
780
+ *
781
+ * The server rejects a plan change unless the caller confirms the
782
+ * plan-change billing terms, so `options.acceptedTerms` is required and
783
+ * always sent. Pass `{ acceptedTerms: true }` only after the user has
784
+ * accepted the terms.
785
+ */
786
+ changePlan(orgId, planId, options) {
787
+ return this.http.put(`/orgs/${orgId}/subscription/plan`, {
788
+ planId,
789
+ acceptedTerms: options?.acceptedTerms === true
790
+ });
644
791
  }
645
792
  /** Cancel subscription */
646
793
  cancel(orgId) {
@@ -681,8 +828,16 @@ var SupportResource = class {
681
828
  createTicket(orgId, data) {
682
829
  return this.http.post(`/orgs/${orgId}/support/tickets`, data);
683
830
  }
684
- /** List support tickets */
685
- listTickets(orgId) {
831
+ /**
832
+ * List support tickets. The API answers `{ tickets, total }`; this
833
+ * returns the tickets. Use `listTicketsWithTotal()` for the total.
834
+ */
835
+ async listTickets(orgId) {
836
+ const res = await this.listTicketsWithTotal(orgId);
837
+ return Array.isArray(res?.tickets) ? res.tickets : [];
838
+ }
839
+ /** List support tickets with the total count. */
840
+ listTicketsWithTotal(orgId) {
686
841
  return this.http.get(`/orgs/${orgId}/support/tickets`);
687
842
  }
688
843
  /** Get ticket statistics */