@iteradian-rpc/sdk 1.0.1 → 1.1.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 CHANGED
@@ -166,11 +166,15 @@ client.clearAccessToken();
166
166
  // Login (token set automatically)
167
167
  const tokens = await client.auth.login({ email: "...", password: "..." });
168
168
 
169
- // Register
170
- const tokens = await client.auth.register({
169
+ // Register — does NOT sign in. Answers { message, email } and emails a
170
+ // confirmation link; log in once the address is confirmed.
171
+ // acceptedTerms is required: pass true only after the user agreed to the
172
+ // Terms of Service, Privacy Policy and DPA (https://iteradian.com/terms,
173
+ // /privacy, /dpa). The server rejects registration (400) otherwise.
174
+ const { message } = await client.auth.register({
171
175
  email: "...",
172
176
  password: "...",
173
- name: "...",
177
+ acceptedTerms: true,
174
178
  });
175
179
 
176
180
  // Refresh token
@@ -184,7 +188,7 @@ const setup = await client.auth.enable2FA({ password: "..." });
184
188
  console.log(`Secret: ${setup.secret}`);
185
189
  console.log(`QR Code: ${setup.qrCode}`);
186
190
  await client.auth.verify2FA({ code: "123456" });
187
- await client.auth.disable2FA({ password: "...", code: "123456" });
191
+ await client.auth.disable2FA("password", "123456"); // password + current 6-digit TOTP code
188
192
 
189
193
  // Magic Link
190
194
  await client.auth.sendMagicLink({ email: "user@example.com" });
@@ -208,11 +212,23 @@ await client.organizations.delete(orgId);
208
212
 
209
213
  // Members
210
214
  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
215
  await client.organizations.removeMember(orgId, memberId);
216
+
217
+ // Invitations — inviting creates a pending invite; the invitee becomes a
218
+ // member only after accepting it (signed in, verified email).
219
+ const invite = await client.organizations.inviteMember(orgId, {
220
+ email: "user@example.com",
221
+ role: "developer",
222
+ }); // { id, email, role, status: "pending", expiresAt, createdAt }
223
+ const open = await client.organizations.listInvites(orgId);
224
+ await client.organizations.revokeInvite(orgId, invite.id);
225
+
226
+ // As the invitee
227
+ const { invites } = await client.organizations.listMyInvites();
228
+ await client.organizations.acceptInvite(invites[0].id); // or declineInvite()
229
+ // A user who has not accepted the current terms version gets 403
230
+ // (TERMS_ACCEPTANCE_REQUIRED); once they agree, accept with:
231
+ await client.organizations.acceptInvite(invites[0].id, { acceptedTerms: true });
216
232
  ```
217
233
 
218
234
  ### API Keys (`client.apiKeys`)
@@ -321,7 +337,11 @@ const stats = await client.logs.getStats(orgId, { period: "24h" });
321
337
 
322
338
  ```typescript
323
339
  const sub = await client.subscriptions.get(orgId);
324
- const updated = await client.subscriptions.changePlan(orgId, { planId: "pro" });
340
+ // The caller confirms the user accepted the plan-change billing terms; the
341
+ // server rejects the change (400) unless acceptedTerms is true.
342
+ const updated = await client.subscriptions.changePlan(orgId, "pro", {
343
+ acceptedTerms: true,
344
+ });
325
345
  const cancelled = await client.subscriptions.cancel(orgId);
326
346
  const reactivated = await client.subscriptions.reactivate(orgId);
327
347
  const invoices = await client.subscriptions.getInvoices(orgId);
@@ -365,7 +385,8 @@ All types are exported from the package and defined in `src/types.ts` (538 lines
365
385
  | Type | Fields |
366
386
  | ----------------- | ------------------------------------- |
367
387
  | `LoginRequest` | `email`, `password`, `twoFactorCode?` |
368
- | `RegisterRequest` | `email`, `password`, `name` |
388
+ | `RegisterRequest` | `email`, `password` |
389
+ | `RegisterResponse` | `message`, `email` (no tokens) |
369
390
  | `AuthTokens` | `accessToken`, `refreshToken`, `user` |
370
391
  | `TwoFASetup` | `secret`, `qrCode` |
371
392
 
@@ -377,6 +398,9 @@ All types are exported from the package and defined in `src/types.ts` (538 lines
377
398
  | `OrgMember` | `id`, `userId`, `email`, `role`, `joinedAt` |
378
399
  | `CreateOrgRequest` | `name`, `slug` |
379
400
  | `InviteMemberRequest` | `email`, `role` |
401
+ | `OrgInvite` | `id`, `email`, `role`, `status`, `expiresAt`, `createdAt`, `invitedBy?` |
402
+ | `MyInvites` | `emailVerified`, `invites` (`MyInvite[]`) |
403
+ | `InviteAcceptance` | `organizationId`, `membershipId`, `role` |
380
404
 
381
405
  ### API Key Types
382
406
 
@@ -449,6 +473,16 @@ try {
449
473
  }
450
474
  ```
451
475
 
476
+ ### Terms acceptance (403 `TERMS_ACCEPTANCE_REQUIRED`)
477
+
478
+ After Iteradian publishes a new version of the Terms of Service, Privacy
479
+ Policy or DPA, any write (POST/PUT/PATCH/DELETE) made with a user JWT may
480
+ answer `IteradianError` with `statusCode` 403 until the user accepts the new
481
+ version in the dashboard (the response body carries
482
+ `code: "TERMS_ACCEPTANCE_REQUIRED"`, `termsVersion` and `termsUrl`). API keys
483
+ and agent tokens are unaffected. `organizations.acceptInvite(id, {
484
+ acceptedTerms: true })` records the acceptance as part of joining.
485
+
452
486
  On a gateway call the same error also carries the JSON-RPC detail, which is how
453
487
  you tell "wait a second" from "you are out of quota until the period rolls
454
488
  over":
@@ -465,6 +499,9 @@ try {
465
499
  if (err instanceof IteradianError) {
466
500
  if (err.isRateLimited) {
467
501
  // -32005. Wait err.retryAfter seconds and try again.
502
+ } else if (err.isDailyLimitReached) {
503
+ // -32008. This API key's daily limit is used up. err.data carries
504
+ // { dailyLimit, used, cost, resetsAt }; resetsAt is the next 00:00 UTC.
468
505
  } else if (err.isQuotaExhausted) {
469
506
  // -32006 or -32007. Retrying will not help: err.data.resetsAt says when
470
507
  // the allowance returns, and the cap needs a plan change.
@@ -489,8 +526,9 @@ The SDK automatically retries:
489
526
  - **5xx Server Errors** — with exponential backoff
490
527
  - **429 Too Many Requests**, but **only** `-32005` (rate or concurrency limit).
491
528
  `-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.
529
+ recover until the billing period rolls over, and `-32008` (per-API-key daily
530
+ limit) not until `error.data.resetsAt` (the next 00:00 UTC), so retrying
531
+ them burns your time for a guaranteed 429.
494
532
 
495
533
  Backoff formula: `min(1000 * 2^(attempt-1), 10000)` ms, or the gateway's own
496
534
  `retryAfter` hint when it gives one — capped at 30 seconds either way.
@@ -622,10 +660,61 @@ This SDK takes both, and defaults the gateway to `https://rpc.iteradian.com`.
622
660
  organization holds. Creating more keys does not raise them.
623
661
  - The gateway returns HTTP 429 with a JSON-RPC error body:
624
662
  `-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.
663
+ quota exhausted, `-32007` overage spend cap reached, `-32008` the API key's
664
+ own daily limit reached (`error.data = { dailyLimit, used, cost, resetsAt }`).
665
+ None of the last three recover before `resetsAt` (the billing period roll-over,
666
+ or the next 00:00 UTC for `-32008`), so retrying them is wasted work.
667
+
668
+ Plans (defaults; an admin can change them): Free 25 rps / 3M per month with no
669
+ overage (requests stop at the quota, no card needed), Developer 100 rps / 5M
670
+ with overage at $6 per million, Professional 500 rps / 30M at $4.50 per million,
671
+ Dedicated per contract from $4 per million. Trials are offered on Developer
672
+ only; a trial that ends unpaid falls back to Free. See `sdks/SDK_CONTRACT.md`
673
+ for the full table.
674
+
675
+ ### WebSocket
676
+
677
+ The gateway also serves JSON-RPC over WebSocket at
678
+ `wss://rpc.iteradian.com/ws/v1/{network}`. This SDK does not wrap it on
679
+ purpose: connect with any WebSocket client, such as ethers
680
+ `WebSocketProvider`, viem's `webSocket()` transport, or the built-in
681
+ `WebSocket` in browsers and Node 22+. Authenticate with the
682
+ `X-Api-Key` header, `Authorization: Bearer <key>`, or `?apiKey=<key>` on the
683
+ URL (browsers cannot set headers on a WebSocket).
627
684
 
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.
685
+ ```typescript
686
+ const ws = new WebSocket(
687
+ "wss://rpc.iteradian.com/ws/v1/eth-mainnet?apiKey=itrd_live_...",
688
+ );
689
+
690
+ ws.addEventListener("open", () => {
691
+ ws.send(JSON.stringify({
692
+ jsonrpc: "2.0", id: 1, method: "eth_subscribe", params: ["newHeads"],
693
+ }));
694
+ });
695
+
696
+ ws.addEventListener("message", (event) => {
697
+ const msg = JSON.parse(event.data);
698
+ if (msg.method === "eth_subscription") {
699
+ console.log("new head", msg.params.result.number);
700
+ }
701
+ });
702
+
703
+ ws.addEventListener("close", (event) => {
704
+ // 1012: node restarted, reconnect and re-subscribe. 4003: key revoked, stop.
705
+ console.log("closed", event.code);
706
+ });
707
+ ```
630
708
 
631
- **WebSocket is not available.** The gateway serves HTTPS JSON-RPC only.
709
+ - Each message you send is charged like an HTTP request (a batch of N costs N).
710
+ Subscription notifications pushed to you are not charged.
711
+ - A message refused by a limit gets an ordinary JSON-RPC error under that
712
+ call's `id`, with the same codes as above (`-32005` to `-32008`). The socket
713
+ stays open.
714
+ - An organization can hold `max(5, floor(concurrency / 4))` streams at once;
715
+ past that the upgrade is refused with HTTP 429. Other upgrade failures: 400
716
+ bad path, 401/403 bad key, 404 unknown network, 503 no WebSocket-capable node.
717
+ - Close code `1012` means the upstream node restarted: reconnect and
718
+ re-subscribe. `4003` means the key was revoked or the organization suspended
719
+ (keys are re-checked every 60 s): do not reconnect.
720
+ - The server pings every 30 s. Messages are limited to 1 MB.
package/dist/index.d.mts CHANGED
@@ -1,6 +1,13 @@
1
1
  interface RegisterRequest {
2
2
  email: string;
3
3
  password: string;
4
+ /**
5
+ * The caller confirms the user agreed to the Terms of Service, Privacy
6
+ * Policy and DPA (https://iteradian.com/terms, /privacy, /dpa). Always
7
+ * sent; the server rejects registration (400) unless this is `true`.
8
+ */
9
+ acceptedTerms: boolean;
10
+ /** @deprecated Ignored by the API. */
4
11
  organizationName?: string;
5
12
  }
6
13
  interface LoginRequest {
@@ -9,6 +16,15 @@ interface LoginRequest {
9
16
  twoFactorCode?: string;
10
17
  backupCode?: string;
11
18
  }
19
+ /**
20
+ * What `POST /auth/register` answers — whether or not the address already has
21
+ * an account (so it cannot be used to probe for accounts). No session is
22
+ * created: the user confirms their address from the email, then logs in.
23
+ */
24
+ interface RegisterResponse {
25
+ message: string;
26
+ email: string;
27
+ }
12
28
  interface AuthTokens {
13
29
  accessToken: string;
14
30
  refreshToken: string;
@@ -49,6 +65,53 @@ interface OrgMember {
49
65
  role: OrgRole;
50
66
  joinedAt: string;
51
67
  }
68
+ /** An invitation to join an organization, as its owners/admins see it. */
69
+ interface OrgInvite {
70
+ id: string;
71
+ email: string;
72
+ role: OrgRole;
73
+ /** "expired" invitations stay listed until revoked or re-sent. */
74
+ status: "pending" | "expired";
75
+ expiresAt: string;
76
+ createdAt: string;
77
+ /** Email of the member who sent it. */
78
+ invitedBy?: string | null;
79
+ }
80
+ /** An invitation addressed to the signed-in user. */
81
+ interface MyInvite {
82
+ id: string;
83
+ role: OrgRole;
84
+ expiresAt: string;
85
+ createdAt: string;
86
+ invitedBy: string | null;
87
+ organization: {
88
+ id: string;
89
+ name: string;
90
+ avatarUrl?: string | null;
91
+ avatarUrlDark?: string | null;
92
+ };
93
+ }
94
+ interface MyInvites {
95
+ /** Invitations can only be accepted once the user's email is verified. */
96
+ emailVerified: boolean;
97
+ invites: MyInvite[];
98
+ }
99
+ /** The membership created by accepting an invitation. */
100
+ /** Options for `organizations.acceptInvite`. */
101
+ interface AcceptInviteOptions {
102
+ /**
103
+ * The caller confirms the user agreed to the current Terms of Service,
104
+ * Privacy Policy and DPA. Only needed when the user has not accepted the
105
+ * current terms version yet; without it the API answers 403
106
+ * `TERMS_ACCEPTANCE_REQUIRED`. Sent only when given.
107
+ */
108
+ acceptedTerms?: boolean;
109
+ }
110
+ interface InviteAcceptance {
111
+ organizationId: string;
112
+ membershipId: string;
113
+ role: OrgRole;
114
+ }
52
115
  interface UserPermissions {
53
116
  role: OrgRole;
54
117
  roleLabel: string;
@@ -349,6 +412,14 @@ interface LogQueryParams {
349
412
  sortBy?: "timestamp" | "latencyMs" | "statusCode";
350
413
  sortOrder?: "asc" | "desc";
351
414
  }
415
+ /** Options for `subscriptions.changePlan`. */
416
+ interface ChangePlanOptions {
417
+ /**
418
+ * The caller confirms the user accepted the plan-change billing terms.
419
+ * The server rejects the change (400) unless this is `true`.
420
+ */
421
+ acceptedTerms: boolean;
422
+ }
352
423
  interface Subscription {
353
424
  id: string;
354
425
  organizationId: string;
@@ -377,7 +448,21 @@ interface PlanLimits {
377
448
  endpoints: number;
378
449
  teamMembers: number;
379
450
  logRetentionDays: number;
380
- }
451
+ /**
452
+ * Limits sold as something other than a plain number, keyed by the API's
453
+ * limit name (`rps`, `concurrency`, `maxApiKeys`, `monthlyRequests`,
454
+ * `overageRatePer1k`, `overageCapUsd`). `"unlimited"`: not enforced per
455
+ * plan. `"custom"`: negotiated per contract. Such a limit carries no number.
456
+ * Absent on plans where every limit is a number.
457
+ */
458
+ limitModes?: Partial<Record<PlanLimitKey, PlanLimitMode>>;
459
+ /** Display text for those limits, e.g. "Quoted per contract". */
460
+ limitLabels?: Partial<Record<PlanLimitKey, string>>;
461
+ }
462
+ /** How a plan limit is sold. Absent from `limitModes` means a plain number. */
463
+ type PlanLimitMode = "unlimited" | "custom";
464
+ /** Limit names that may appear in `PlanLimits.limitModes`. */
465
+ type PlanLimitKey = "rps" | "concurrency" | "maxApiKeys" | "monthlyRequests" | "overageRatePer1k" | "overageCapUsd";
381
466
  interface Invoice {
382
467
  id: string;
383
468
  amount: number;
@@ -482,6 +567,8 @@ declare class IteradianError extends Error {
482
567
  * -32005 rate limit or concurrency limit exceeded (retry shortly)
483
568
  * -32006 monthly quota exhausted (retrying will not help until `resetsAt`)
484
569
  * -32007 overage spend limit reached (same — needs a plan change)
570
+ * -32008 per-API-key daily limit reached (no retry until `data.resetsAt`,
571
+ * the next 00:00 UTC)
485
572
  */
486
573
  readonly rpcCode?: number;
487
574
  /** Seconds to wait before retrying, when the gateway supplied one. */
@@ -493,8 +580,18 @@ declare class IteradianError extends Error {
493
580
  retryAfter?: number;
494
581
  data?: Record<string, unknown>;
495
582
  });
496
- /** True when the request failed because the subscription is out of allowance. */
583
+ /**
584
+ * True when the request failed because an allowance is used up and retrying
585
+ * will not help until it resets: the subscription quota (-32006), the
586
+ * overage spend cap (-32007) or the API key's daily limit (-32008).
587
+ */
497
588
  get isQuotaExhausted(): boolean;
589
+ /**
590
+ * True when the API key's own daily limit is reached (-32008). `data` then
591
+ * carries `{ dailyLimit, used, cost, resetsAt }`; `resetsAt` is the next
592
+ * 00:00 UTC.
593
+ */
594
+ get isDailyLimitReached(): boolean;
498
595
  /** True when the request was throttled and is worth retrying. */
499
596
  get isRateLimited(): boolean;
500
597
  }
@@ -530,8 +627,18 @@ declare class HttpClient {
530
627
  declare class AuthResource {
531
628
  private http;
532
629
  constructor(http: HttpClient);
533
- /** Register a new user account */
534
- register(data: RegisterRequest): Promise<AuthTokens>;
630
+ /**
631
+ * Register a new user account. Does not sign in: the API answers
632
+ * `{ message, email }` (the same for an address that already has an
633
+ * account) and emails a confirmation link. Call `login()` once the address
634
+ * is confirmed.
635
+ *
636
+ * The server rejects registration (400) unless the user agreed to the
637
+ * Terms of Service, Privacy Policy and DPA, so `data.acceptedTerms` is
638
+ * required and always sent. Pass `acceptedTerms: true` only after the user
639
+ * has ticked the agreement.
640
+ */
641
+ register(data: RegisterRequest): Promise<RegisterResponse>;
535
642
  /** Login with email/password (optionally with 2FA code) */
536
643
  login(data: LoginRequest): Promise<AuthTokens>;
537
644
  /** Logout current session */
@@ -587,11 +694,37 @@ declare class OrganizationsResource {
587
694
  leave(orgId: string): Promise<void>;
588
695
  /** List organization members */
589
696
  listMembers(orgId: string): Promise<OrgMember[]>;
590
- /** Invite a member to the organization */
697
+ /**
698
+ * Invite someone to the organization by email. Creates (or refreshes) a
699
+ * pending invitation — nobody becomes a member until the invitee accepts
700
+ * it while signed in with a verified address.
701
+ */
591
702
  inviteMember(orgId: string, data: {
592
703
  email: string;
593
704
  role: string;
594
- }): Promise<OrgMember>;
705
+ }): Promise<OrgInvite>;
706
+ /** Open invitations of the organization (owner/admin) */
707
+ listInvites(orgId: string): Promise<OrgInvite[]>;
708
+ /** Revoke an open invitation (owner/admin) */
709
+ revokeInvite(orgId: string, inviteId: string): Promise<{
710
+ message: string;
711
+ }>;
712
+ /** Invitations addressed to the signed-in user */
713
+ listMyInvites(): Promise<MyInvites>;
714
+ /**
715
+ * Accept an invitation addressed to the signed-in user.
716
+ *
717
+ * If the user has not accepted the current terms version yet, the API
718
+ * answers 403 (`TERMS_ACCEPTANCE_REQUIRED`) unless
719
+ * `{ acceptedTerms: true }` is passed — only after the user agreed to the
720
+ * Terms of Service, Privacy Policy and DPA. `acceptedTerms` is sent only
721
+ * when given.
722
+ */
723
+ acceptInvite(inviteId: string, options?: AcceptInviteOptions): Promise<InviteAcceptance>;
724
+ /** Decline an invitation addressed to the signed-in user */
725
+ declineInvite(inviteId: string): Promise<{
726
+ message: string;
727
+ }>;
595
728
  /** Update a member's role */
596
729
  updateMemberRole(orgId: string, memberId: string, role: string): Promise<OrgMember>;
597
730
  /** Remove a member from the organization */
@@ -741,8 +874,15 @@ declare class SubscriptionsResource {
741
874
  constructor(http: HttpClient);
742
875
  /** Get current subscription */
743
876
  get(orgId: string): Promise<Subscription>;
744
- /** Change subscription plan */
745
- changePlan(orgId: string, planId: string): Promise<Subscription>;
877
+ /**
878
+ * Change subscription plan.
879
+ *
880
+ * The server rejects a plan change unless the caller confirms the
881
+ * plan-change billing terms, so `options.acceptedTerms` is required and
882
+ * always sent. Pass `{ acceptedTerms: true }` only after the user has
883
+ * accepted the terms.
884
+ */
885
+ changePlan(orgId: string, planId: string, options: ChangePlanOptions): Promise<Subscription>;
746
886
  /** Cancel subscription */
747
887
  cancel(orgId: string): Promise<Subscription>;
748
888
  /** Reactivate a cancelled subscription */
@@ -837,7 +977,7 @@ declare class RpcResource {
837
977
  *
838
978
  * @example
839
979
  * ```typescript
840
- * import { IteradianClient } from '@iteradian/sdk';
980
+ * import { IteradianClient } from '@iteradian-rpc/sdk';
841
981
  *
842
982
  * const client = new IteradianClient({
843
983
  * baseUrl: 'https://api.iteradian.com/api/v1',
@@ -890,4 +1030,5 @@ declare class IteradianClient {
890
1030
  clearAccessToken(): void;
891
1031
  }
892
1032
 
893
- export { type Alert, type AlertChannel, type AlertCondition, type AlertMetric, type AlertRule, type AlertSeverity, type AlertStatus, AlertsResource, type ApiError, type ApiKey, type ApiKeyAnalytics, type ApiKeyWithSecret, ApiKeysResource, type ApiResponse, AuthResource, type AuthTokens, type CreateAlertChannelRequest, type CreateAlertRuleRequest, type CreateApiKeyRequest, type CreateEndpointRequest, type CreateTicketRequest, type DailyUsage, type DashboardData, DashboardResource, type DataPoint, type Endpoint, type EndpointMetric, type EndpointRegion, type EndpointStatus, EndpointsResource, type HealthStatus, type Invoice, IteradianClient, type IteradianConfig, IteradianError, type JsonRpcError, type JsonRpcRequest, type JsonRpcResponse, type LogFilterOptions, type LogQueryParams, type LogStatus, type LoginRequest, LogsResource, type LogsResponse, type Membership, type Network, type NetworkType, type OrgMember, type OrgRole, type Organization, OrganizationsResource, type PaginatedResponse, type Plan, type PlanLimits, PlansResource, type QuickStats, type RegisterRequest, type RequestLog, RpcResource, type Subscription, SubscriptionsResource, SupportResource, type SupportTicket, type TicketCategory, type TicketMessage, type TicketPriority, type TicketStatus, type TwoFASetup, type UpdateApiKeyRequest, type UpdateEndpointRequest, type UsageByMethod, type UsageByNetwork, type UsageByRegion, UsageResource, type UsageSummary, type User, type UserPermissions };
1033
+ export { AlertsResource, ApiKeysResource, AuthResource, DashboardResource, EndpointsResource, IteradianClient, IteradianError, LogsResource, OrganizationsResource, PlansResource, RpcResource, SubscriptionsResource, SupportResource, UsageResource };
1034
+ export type { AcceptInviteOptions, Alert, AlertChannel, AlertCondition, AlertMetric, AlertRule, AlertSeverity, AlertStatus, ApiError, ApiKey, ApiKeyAnalytics, ApiKeyWithSecret, ApiResponse, AuthTokens, ChangePlanOptions, CreateAlertChannelRequest, CreateAlertRuleRequest, CreateApiKeyRequest, CreateEndpointRequest, CreateTicketRequest, DailyUsage, DashboardData, DataPoint, Endpoint, EndpointMetric, EndpointRegion, EndpointStatus, HealthStatus, InviteAcceptance, Invoice, IteradianConfig, JsonRpcError, JsonRpcRequest, JsonRpcResponse, LogFilterOptions, LogQueryParams, LogStatus, LoginRequest, LogsResponse, Membership, MyInvite, MyInvites, Network, NetworkType, OrgInvite, OrgMember, OrgRole, Organization, PaginatedResponse, Plan, PlanLimitKey, PlanLimitMode, PlanLimits, QuickStats, RegisterRequest, RegisterResponse, RequestLog, Subscription, SupportTicket, TicketCategory, TicketMessage, TicketPriority, TicketStatus, TwoFASetup, UpdateApiKeyRequest, UpdateEndpointRequest, UsageByMethod, UsageByNetwork, UsageByRegion, UsageSummary, User, UserPermissions };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,13 @@
1
1
  interface RegisterRequest {
2
2
  email: string;
3
3
  password: string;
4
+ /**
5
+ * The caller confirms the user agreed to the Terms of Service, Privacy
6
+ * Policy and DPA (https://iteradian.com/terms, /privacy, /dpa). Always
7
+ * sent; the server rejects registration (400) unless this is `true`.
8
+ */
9
+ acceptedTerms: boolean;
10
+ /** @deprecated Ignored by the API. */
4
11
  organizationName?: string;
5
12
  }
6
13
  interface LoginRequest {
@@ -9,6 +16,15 @@ interface LoginRequest {
9
16
  twoFactorCode?: string;
10
17
  backupCode?: string;
11
18
  }
19
+ /**
20
+ * What `POST /auth/register` answers — whether or not the address already has
21
+ * an account (so it cannot be used to probe for accounts). No session is
22
+ * created: the user confirms their address from the email, then logs in.
23
+ */
24
+ interface RegisterResponse {
25
+ message: string;
26
+ email: string;
27
+ }
12
28
  interface AuthTokens {
13
29
  accessToken: string;
14
30
  refreshToken: string;
@@ -49,6 +65,53 @@ interface OrgMember {
49
65
  role: OrgRole;
50
66
  joinedAt: string;
51
67
  }
68
+ /** An invitation to join an organization, as its owners/admins see it. */
69
+ interface OrgInvite {
70
+ id: string;
71
+ email: string;
72
+ role: OrgRole;
73
+ /** "expired" invitations stay listed until revoked or re-sent. */
74
+ status: "pending" | "expired";
75
+ expiresAt: string;
76
+ createdAt: string;
77
+ /** Email of the member who sent it. */
78
+ invitedBy?: string | null;
79
+ }
80
+ /** An invitation addressed to the signed-in user. */
81
+ interface MyInvite {
82
+ id: string;
83
+ role: OrgRole;
84
+ expiresAt: string;
85
+ createdAt: string;
86
+ invitedBy: string | null;
87
+ organization: {
88
+ id: string;
89
+ name: string;
90
+ avatarUrl?: string | null;
91
+ avatarUrlDark?: string | null;
92
+ };
93
+ }
94
+ interface MyInvites {
95
+ /** Invitations can only be accepted once the user's email is verified. */
96
+ emailVerified: boolean;
97
+ invites: MyInvite[];
98
+ }
99
+ /** The membership created by accepting an invitation. */
100
+ /** Options for `organizations.acceptInvite`. */
101
+ interface AcceptInviteOptions {
102
+ /**
103
+ * The caller confirms the user agreed to the current Terms of Service,
104
+ * Privacy Policy and DPA. Only needed when the user has not accepted the
105
+ * current terms version yet; without it the API answers 403
106
+ * `TERMS_ACCEPTANCE_REQUIRED`. Sent only when given.
107
+ */
108
+ acceptedTerms?: boolean;
109
+ }
110
+ interface InviteAcceptance {
111
+ organizationId: string;
112
+ membershipId: string;
113
+ role: OrgRole;
114
+ }
52
115
  interface UserPermissions {
53
116
  role: OrgRole;
54
117
  roleLabel: string;
@@ -349,6 +412,14 @@ interface LogQueryParams {
349
412
  sortBy?: "timestamp" | "latencyMs" | "statusCode";
350
413
  sortOrder?: "asc" | "desc";
351
414
  }
415
+ /** Options for `subscriptions.changePlan`. */
416
+ interface ChangePlanOptions {
417
+ /**
418
+ * The caller confirms the user accepted the plan-change billing terms.
419
+ * The server rejects the change (400) unless this is `true`.
420
+ */
421
+ acceptedTerms: boolean;
422
+ }
352
423
  interface Subscription {
353
424
  id: string;
354
425
  organizationId: string;
@@ -377,7 +448,21 @@ interface PlanLimits {
377
448
  endpoints: number;
378
449
  teamMembers: number;
379
450
  logRetentionDays: number;
380
- }
451
+ /**
452
+ * Limits sold as something other than a plain number, keyed by the API's
453
+ * limit name (`rps`, `concurrency`, `maxApiKeys`, `monthlyRequests`,
454
+ * `overageRatePer1k`, `overageCapUsd`). `"unlimited"`: not enforced per
455
+ * plan. `"custom"`: negotiated per contract. Such a limit carries no number.
456
+ * Absent on plans where every limit is a number.
457
+ */
458
+ limitModes?: Partial<Record<PlanLimitKey, PlanLimitMode>>;
459
+ /** Display text for those limits, e.g. "Quoted per contract". */
460
+ limitLabels?: Partial<Record<PlanLimitKey, string>>;
461
+ }
462
+ /** How a plan limit is sold. Absent from `limitModes` means a plain number. */
463
+ type PlanLimitMode = "unlimited" | "custom";
464
+ /** Limit names that may appear in `PlanLimits.limitModes`. */
465
+ type PlanLimitKey = "rps" | "concurrency" | "maxApiKeys" | "monthlyRequests" | "overageRatePer1k" | "overageCapUsd";
381
466
  interface Invoice {
382
467
  id: string;
383
468
  amount: number;
@@ -482,6 +567,8 @@ declare class IteradianError extends Error {
482
567
  * -32005 rate limit or concurrency limit exceeded (retry shortly)
483
568
  * -32006 monthly quota exhausted (retrying will not help until `resetsAt`)
484
569
  * -32007 overage spend limit reached (same — needs a plan change)
570
+ * -32008 per-API-key daily limit reached (no retry until `data.resetsAt`,
571
+ * the next 00:00 UTC)
485
572
  */
486
573
  readonly rpcCode?: number;
487
574
  /** Seconds to wait before retrying, when the gateway supplied one. */
@@ -493,8 +580,18 @@ declare class IteradianError extends Error {
493
580
  retryAfter?: number;
494
581
  data?: Record<string, unknown>;
495
582
  });
496
- /** True when the request failed because the subscription is out of allowance. */
583
+ /**
584
+ * True when the request failed because an allowance is used up and retrying
585
+ * will not help until it resets: the subscription quota (-32006), the
586
+ * overage spend cap (-32007) or the API key's daily limit (-32008).
587
+ */
497
588
  get isQuotaExhausted(): boolean;
589
+ /**
590
+ * True when the API key's own daily limit is reached (-32008). `data` then
591
+ * carries `{ dailyLimit, used, cost, resetsAt }`; `resetsAt` is the next
592
+ * 00:00 UTC.
593
+ */
594
+ get isDailyLimitReached(): boolean;
498
595
  /** True when the request was throttled and is worth retrying. */
499
596
  get isRateLimited(): boolean;
500
597
  }
@@ -530,8 +627,18 @@ declare class HttpClient {
530
627
  declare class AuthResource {
531
628
  private http;
532
629
  constructor(http: HttpClient);
533
- /** Register a new user account */
534
- register(data: RegisterRequest): Promise<AuthTokens>;
630
+ /**
631
+ * Register a new user account. Does not sign in: the API answers
632
+ * `{ message, email }` (the same for an address that already has an
633
+ * account) and emails a confirmation link. Call `login()` once the address
634
+ * is confirmed.
635
+ *
636
+ * The server rejects registration (400) unless the user agreed to the
637
+ * Terms of Service, Privacy Policy and DPA, so `data.acceptedTerms` is
638
+ * required and always sent. Pass `acceptedTerms: true` only after the user
639
+ * has ticked the agreement.
640
+ */
641
+ register(data: RegisterRequest): Promise<RegisterResponse>;
535
642
  /** Login with email/password (optionally with 2FA code) */
536
643
  login(data: LoginRequest): Promise<AuthTokens>;
537
644
  /** Logout current session */
@@ -587,11 +694,37 @@ declare class OrganizationsResource {
587
694
  leave(orgId: string): Promise<void>;
588
695
  /** List organization members */
589
696
  listMembers(orgId: string): Promise<OrgMember[]>;
590
- /** Invite a member to the organization */
697
+ /**
698
+ * Invite someone to the organization by email. Creates (or refreshes) a
699
+ * pending invitation — nobody becomes a member until the invitee accepts
700
+ * it while signed in with a verified address.
701
+ */
591
702
  inviteMember(orgId: string, data: {
592
703
  email: string;
593
704
  role: string;
594
- }): Promise<OrgMember>;
705
+ }): Promise<OrgInvite>;
706
+ /** Open invitations of the organization (owner/admin) */
707
+ listInvites(orgId: string): Promise<OrgInvite[]>;
708
+ /** Revoke an open invitation (owner/admin) */
709
+ revokeInvite(orgId: string, inviteId: string): Promise<{
710
+ message: string;
711
+ }>;
712
+ /** Invitations addressed to the signed-in user */
713
+ listMyInvites(): Promise<MyInvites>;
714
+ /**
715
+ * Accept an invitation addressed to the signed-in user.
716
+ *
717
+ * If the user has not accepted the current terms version yet, the API
718
+ * answers 403 (`TERMS_ACCEPTANCE_REQUIRED`) unless
719
+ * `{ acceptedTerms: true }` is passed — only after the user agreed to the
720
+ * Terms of Service, Privacy Policy and DPA. `acceptedTerms` is sent only
721
+ * when given.
722
+ */
723
+ acceptInvite(inviteId: string, options?: AcceptInviteOptions): Promise<InviteAcceptance>;
724
+ /** Decline an invitation addressed to the signed-in user */
725
+ declineInvite(inviteId: string): Promise<{
726
+ message: string;
727
+ }>;
595
728
  /** Update a member's role */
596
729
  updateMemberRole(orgId: string, memberId: string, role: string): Promise<OrgMember>;
597
730
  /** Remove a member from the organization */
@@ -741,8 +874,15 @@ declare class SubscriptionsResource {
741
874
  constructor(http: HttpClient);
742
875
  /** Get current subscription */
743
876
  get(orgId: string): Promise<Subscription>;
744
- /** Change subscription plan */
745
- changePlan(orgId: string, planId: string): Promise<Subscription>;
877
+ /**
878
+ * Change subscription plan.
879
+ *
880
+ * The server rejects a plan change unless the caller confirms the
881
+ * plan-change billing terms, so `options.acceptedTerms` is required and
882
+ * always sent. Pass `{ acceptedTerms: true }` only after the user has
883
+ * accepted the terms.
884
+ */
885
+ changePlan(orgId: string, planId: string, options: ChangePlanOptions): Promise<Subscription>;
746
886
  /** Cancel subscription */
747
887
  cancel(orgId: string): Promise<Subscription>;
748
888
  /** Reactivate a cancelled subscription */
@@ -837,7 +977,7 @@ declare class RpcResource {
837
977
  *
838
978
  * @example
839
979
  * ```typescript
840
- * import { IteradianClient } from '@iteradian/sdk';
980
+ * import { IteradianClient } from '@iteradian-rpc/sdk';
841
981
  *
842
982
  * const client = new IteradianClient({
843
983
  * baseUrl: 'https://api.iteradian.com/api/v1',
@@ -890,4 +1030,5 @@ declare class IteradianClient {
890
1030
  clearAccessToken(): void;
891
1031
  }
892
1032
 
893
- export { type Alert, type AlertChannel, type AlertCondition, type AlertMetric, type AlertRule, type AlertSeverity, type AlertStatus, AlertsResource, type ApiError, type ApiKey, type ApiKeyAnalytics, type ApiKeyWithSecret, ApiKeysResource, type ApiResponse, AuthResource, type AuthTokens, type CreateAlertChannelRequest, type CreateAlertRuleRequest, type CreateApiKeyRequest, type CreateEndpointRequest, type CreateTicketRequest, type DailyUsage, type DashboardData, DashboardResource, type DataPoint, type Endpoint, type EndpointMetric, type EndpointRegion, type EndpointStatus, EndpointsResource, type HealthStatus, type Invoice, IteradianClient, type IteradianConfig, IteradianError, type JsonRpcError, type JsonRpcRequest, type JsonRpcResponse, type LogFilterOptions, type LogQueryParams, type LogStatus, type LoginRequest, LogsResource, type LogsResponse, type Membership, type Network, type NetworkType, type OrgMember, type OrgRole, type Organization, OrganizationsResource, type PaginatedResponse, type Plan, type PlanLimits, PlansResource, type QuickStats, type RegisterRequest, type RequestLog, RpcResource, type Subscription, SubscriptionsResource, SupportResource, type SupportTicket, type TicketCategory, type TicketMessage, type TicketPriority, type TicketStatus, type TwoFASetup, type UpdateApiKeyRequest, type UpdateEndpointRequest, type UsageByMethod, type UsageByNetwork, type UsageByRegion, UsageResource, type UsageSummary, type User, type UserPermissions };
1033
+ export { AlertsResource, ApiKeysResource, AuthResource, DashboardResource, EndpointsResource, IteradianClient, IteradianError, LogsResource, OrganizationsResource, PlansResource, RpcResource, SubscriptionsResource, SupportResource, UsageResource };
1034
+ export type { AcceptInviteOptions, Alert, AlertChannel, AlertCondition, AlertMetric, AlertRule, AlertSeverity, AlertStatus, ApiError, ApiKey, ApiKeyAnalytics, ApiKeyWithSecret, ApiResponse, AuthTokens, ChangePlanOptions, CreateAlertChannelRequest, CreateAlertRuleRequest, CreateApiKeyRequest, CreateEndpointRequest, CreateTicketRequest, DailyUsage, DashboardData, DataPoint, Endpoint, EndpointMetric, EndpointRegion, EndpointStatus, HealthStatus, InviteAcceptance, Invoice, IteradianConfig, JsonRpcError, JsonRpcRequest, JsonRpcResponse, LogFilterOptions, LogQueryParams, LogStatus, LoginRequest, LogsResponse, Membership, MyInvite, MyInvites, Network, NetworkType, OrgInvite, OrgMember, OrgRole, Organization, PaginatedResponse, Plan, PlanLimitKey, PlanLimitMode, PlanLimits, QuickStats, RegisterRequest, RegisterResponse, RequestLog, Subscription, SupportTicket, TicketCategory, TicketMessage, TicketPriority, TicketStatus, TwoFASetup, UpdateApiKeyRequest, UpdateEndpointRequest, UsageByMethod, UsageByNetwork, UsageByRegion, UsageSummary, User, UserPermissions };
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() {
@@ -150,7 +162,7 @@ var HttpClient = class {
150
162
  const rpc = errorBody?.error;
151
163
  const rpcCode = typeof rpc?.code === "number" ? rpc.code : void 0;
152
164
  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;
165
+ const worthRetrying = response.status >= 500 || response.status === 429 && rpcCode !== -32006 && rpcCode !== -32007 && rpcCode !== -32008;
154
166
  if (this.retry && attempt < this.maxRetries && worthRetrying && isReplayableBody(body) && !controller.signal.aborted) {
155
167
  const backoff = Math.min(1e3 * 2 ** (attempt - 1), 1e4);
156
168
  const delay = Math.min(
@@ -236,9 +248,22 @@ var AuthResource = class {
236
248
  constructor(http) {
237
249
  this.http = http;
238
250
  }
239
- /** Register a new user account */
251
+ /**
252
+ * Register a new user account. Does not sign in: the API answers
253
+ * `{ message, email }` (the same for an address that already has an
254
+ * account) and emails a confirmation link. Call `login()` once the address
255
+ * is confirmed.
256
+ *
257
+ * The server rejects registration (400) unless the user agreed to the
258
+ * Terms of Service, Privacy Policy and DPA, so `data.acceptedTerms` is
259
+ * required and always sent. Pass `acceptedTerms: true` only after the user
260
+ * has ticked the agreement.
261
+ */
240
262
  register(data) {
241
- return this.http.post("/auth/register", data);
263
+ return this.http.post("/auth/register", {
264
+ ...data,
265
+ acceptedTerms: data?.acceptedTerms === true
266
+ });
242
267
  }
243
268
  /** Login with email/password (optionally with 2FA code) */
244
269
  async login(data) {
@@ -337,10 +362,47 @@ var OrganizationsResource = class {
337
362
  listMembers(orgId) {
338
363
  return this.http.get(`/orgs/${orgId}/members`);
339
364
  }
340
- /** Invite a member to the organization */
365
+ /**
366
+ * Invite someone to the organization by email. Creates (or refreshes) a
367
+ * pending invitation — nobody becomes a member until the invitee accepts
368
+ * it while signed in with a verified address.
369
+ */
341
370
  inviteMember(orgId, data) {
342
371
  return this.http.post(`/orgs/${orgId}/members`, data);
343
372
  }
373
+ /** Open invitations of the organization (owner/admin) */
374
+ listInvites(orgId) {
375
+ return this.http.get(`/orgs/${orgId}/invites`);
376
+ }
377
+ /** Revoke an open invitation (owner/admin) */
378
+ revokeInvite(orgId, inviteId) {
379
+ return this.http.delete(`/orgs/${orgId}/invites/${inviteId}`);
380
+ }
381
+ /** Invitations addressed to the signed-in user */
382
+ listMyInvites() {
383
+ return this.http.get("/invites");
384
+ }
385
+ /**
386
+ * Accept an invitation addressed to the signed-in user.
387
+ *
388
+ * If the user has not accepted the current terms version yet, the API
389
+ * answers 403 (`TERMS_ACCEPTANCE_REQUIRED`) unless
390
+ * `{ acceptedTerms: true }` is passed — only after the user agreed to the
391
+ * Terms of Service, Privacy Policy and DPA. `acceptedTerms` is sent only
392
+ * when given.
393
+ */
394
+ acceptInvite(inviteId, options) {
395
+ if (options?.acceptedTerms !== void 0) {
396
+ return this.http.post(`/invites/${inviteId}/accept`, {
397
+ acceptedTerms: options.acceptedTerms === true
398
+ });
399
+ }
400
+ return this.http.post(`/invites/${inviteId}/accept`);
401
+ }
402
+ /** Decline an invitation addressed to the signed-in user */
403
+ declineInvite(inviteId) {
404
+ return this.http.post(`/invites/${inviteId}/decline`);
405
+ }
344
406
  /** Update a member's role */
345
407
  updateMemberRole(orgId, memberId, role) {
346
408
  return this.http.put(`/orgs/${orgId}/members/${memberId}`, { role });
@@ -638,9 +700,19 @@ var SubscriptionsResource = class {
638
700
  get(orgId) {
639
701
  return this.http.get(`/orgs/${orgId}/subscription`);
640
702
  }
641
- /** Change subscription plan */
642
- changePlan(orgId, planId) {
643
- return this.http.put(`/orgs/${orgId}/subscription/plan`, { planId });
703
+ /**
704
+ * Change subscription plan.
705
+ *
706
+ * The server rejects a plan change unless the caller confirms the
707
+ * plan-change billing terms, so `options.acceptedTerms` is required and
708
+ * always sent. Pass `{ acceptedTerms: true }` only after the user has
709
+ * accepted the terms.
710
+ */
711
+ changePlan(orgId, planId, options) {
712
+ return this.http.put(`/orgs/${orgId}/subscription/plan`, {
713
+ planId,
714
+ acceptedTerms: options?.acceptedTerms === true
715
+ });
644
716
  }
645
717
  /** Cancel subscription */
646
718
  cancel(orgId) {
package/dist/index.mjs CHANGED
@@ -9,9 +9,21 @@ var IteradianError = class extends Error {
9
9
  this.retryAfter = rpc?.retryAfter;
10
10
  this.data = rpc?.data;
11
11
  }
12
- /** True when the request failed because the subscription is out of allowance. */
12
+ /**
13
+ * True when the request failed because an allowance is used up and retrying
14
+ * will not help until it resets: the subscription quota (-32006), the
15
+ * overage spend cap (-32007) or the API key's daily limit (-32008).
16
+ */
13
17
  get isQuotaExhausted() {
14
- return this.rpcCode === -32006 || this.rpcCode === -32007;
18
+ return this.rpcCode === -32006 || this.rpcCode === -32007 || this.rpcCode === -32008;
19
+ }
20
+ /**
21
+ * True when the API key's own daily limit is reached (-32008). `data` then
22
+ * carries `{ dailyLimit, used, cost, resetsAt }`; `resetsAt` is the next
23
+ * 00:00 UTC.
24
+ */
25
+ get isDailyLimitReached() {
26
+ return this.rpcCode === -32008;
15
27
  }
16
28
  /** True when the request was throttled and is worth retrying. */
17
29
  get isRateLimited() {
@@ -111,7 +123,7 @@ var HttpClient = class {
111
123
  const rpc = errorBody?.error;
112
124
  const rpcCode = typeof rpc?.code === "number" ? rpc.code : void 0;
113
125
  const retryAfter = typeof rpc?.data?.retryAfter === "number" ? rpc.data.retryAfter : void 0;
114
- const worthRetrying = response.status >= 500 || response.status === 429 && rpcCode !== -32006 && rpcCode !== -32007;
126
+ const worthRetrying = response.status >= 500 || response.status === 429 && rpcCode !== -32006 && rpcCode !== -32007 && rpcCode !== -32008;
115
127
  if (this.retry && attempt < this.maxRetries && worthRetrying && isReplayableBody(body) && !controller.signal.aborted) {
116
128
  const backoff = Math.min(1e3 * 2 ** (attempt - 1), 1e4);
117
129
  const delay = Math.min(
@@ -197,9 +209,22 @@ var AuthResource = class {
197
209
  constructor(http) {
198
210
  this.http = http;
199
211
  }
200
- /** Register a new user account */
212
+ /**
213
+ * Register a new user account. Does not sign in: the API answers
214
+ * `{ message, email }` (the same for an address that already has an
215
+ * account) and emails a confirmation link. Call `login()` once the address
216
+ * is confirmed.
217
+ *
218
+ * The server rejects registration (400) unless the user agreed to the
219
+ * Terms of Service, Privacy Policy and DPA, so `data.acceptedTerms` is
220
+ * required and always sent. Pass `acceptedTerms: true` only after the user
221
+ * has ticked the agreement.
222
+ */
201
223
  register(data) {
202
- return this.http.post("/auth/register", data);
224
+ return this.http.post("/auth/register", {
225
+ ...data,
226
+ acceptedTerms: data?.acceptedTerms === true
227
+ });
203
228
  }
204
229
  /** Login with email/password (optionally with 2FA code) */
205
230
  async login(data) {
@@ -298,10 +323,47 @@ var OrganizationsResource = class {
298
323
  listMembers(orgId) {
299
324
  return this.http.get(`/orgs/${orgId}/members`);
300
325
  }
301
- /** Invite a member to the organization */
326
+ /**
327
+ * Invite someone to the organization by email. Creates (or refreshes) a
328
+ * pending invitation — nobody becomes a member until the invitee accepts
329
+ * it while signed in with a verified address.
330
+ */
302
331
  inviteMember(orgId, data) {
303
332
  return this.http.post(`/orgs/${orgId}/members`, data);
304
333
  }
334
+ /** Open invitations of the organization (owner/admin) */
335
+ listInvites(orgId) {
336
+ return this.http.get(`/orgs/${orgId}/invites`);
337
+ }
338
+ /** Revoke an open invitation (owner/admin) */
339
+ revokeInvite(orgId, inviteId) {
340
+ return this.http.delete(`/orgs/${orgId}/invites/${inviteId}`);
341
+ }
342
+ /** Invitations addressed to the signed-in user */
343
+ listMyInvites() {
344
+ return this.http.get("/invites");
345
+ }
346
+ /**
347
+ * Accept an invitation addressed to the signed-in user.
348
+ *
349
+ * If the user has not accepted the current terms version yet, the API
350
+ * answers 403 (`TERMS_ACCEPTANCE_REQUIRED`) unless
351
+ * `{ acceptedTerms: true }` is passed — only after the user agreed to the
352
+ * Terms of Service, Privacy Policy and DPA. `acceptedTerms` is sent only
353
+ * when given.
354
+ */
355
+ acceptInvite(inviteId, options) {
356
+ if (options?.acceptedTerms !== void 0) {
357
+ return this.http.post(`/invites/${inviteId}/accept`, {
358
+ acceptedTerms: options.acceptedTerms === true
359
+ });
360
+ }
361
+ return this.http.post(`/invites/${inviteId}/accept`);
362
+ }
363
+ /** Decline an invitation addressed to the signed-in user */
364
+ declineInvite(inviteId) {
365
+ return this.http.post(`/invites/${inviteId}/decline`);
366
+ }
305
367
  /** Update a member's role */
306
368
  updateMemberRole(orgId, memberId, role) {
307
369
  return this.http.put(`/orgs/${orgId}/members/${memberId}`, { role });
@@ -599,9 +661,19 @@ var SubscriptionsResource = class {
599
661
  get(orgId) {
600
662
  return this.http.get(`/orgs/${orgId}/subscription`);
601
663
  }
602
- /** Change subscription plan */
603
- changePlan(orgId, planId) {
604
- return this.http.put(`/orgs/${orgId}/subscription/plan`, { planId });
664
+ /**
665
+ * Change subscription plan.
666
+ *
667
+ * The server rejects a plan change unless the caller confirms the
668
+ * plan-change billing terms, so `options.acceptedTerms` is required and
669
+ * always sent. Pass `{ acceptedTerms: true }` only after the user has
670
+ * accepted the terms.
671
+ */
672
+ changePlan(orgId, planId, options) {
673
+ return this.http.put(`/orgs/${orgId}/subscription/plan`, {
674
+ planId,
675
+ acceptedTerms: options?.acceptedTerms === true
676
+ });
605
677
  }
606
678
  /** Cancel subscription */
607
679
  cancel(orgId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iteradian-rpc/sdk",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "Official Iteradian Control Plane SDK for JavaScript/TypeScript",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -20,7 +20,7 @@
20
20
  "build": "tsup src/index.ts --format cjs,esm --dts",
21
21
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
22
22
  "lint": "tsc --noEmit",
23
- "test": "jest"
23
+ "test": "node --test test/account.test.mjs"
24
24
  },
25
25
  "keywords": [
26
26
  "iteradian",
@@ -33,22 +33,14 @@
33
33
  "author": "Iteradian",
34
34
  "license": "MIT",
35
35
  "devDependencies": {
36
- "tsup": "^8.5.1",
36
+ "tsup": "^9.0.0",
37
37
  "typescript": "^6.0.3",
38
- "@types/node": "^25.6.0"
38
+ "@types/node": "^26.6.5"
39
39
  },
40
40
  "engines": {
41
41
  "node": ">=16.0.0"
42
42
  },
43
- "repository": {
44
- "type": "git",
45
- "url": "git+https://github.com/IteRaDian-RPC/iteradian-control-plane.git",
46
- "directory": "sdks/typescript"
47
- },
48
- "homepage": "https://github.com/IteRaDian-RPC/iteradian-control-plane/tree/main/sdks/typescript#readme",
49
- "bugs": {
50
- "url": "https://github.com/IteRaDian-RPC/iteradian-control-plane/issues"
51
- },
43
+ "homepage": "https://iteradian.com",
52
44
  "publishConfig": {
53
45
  "access": "public"
54
46
  }