@kaiban/sdk 0.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.
Files changed (86) hide show
  1. package/README.md +225 -0
  2. package/dist/index.d.ts +15 -0
  3. package/dist/index.js +15 -0
  4. package/dist/lib/client.d.ts +65 -0
  5. package/dist/lib/client.js +51 -0
  6. package/dist/lib/http/HttpClient.d.ts +16 -0
  7. package/dist/lib/http/HttpClient.js +237 -0
  8. package/dist/lib/http/errors.d.ts +50 -0
  9. package/dist/lib/http/errors.js +126 -0
  10. package/dist/lib/http/types.d.ts +40 -0
  11. package/dist/lib/http/types.js +1 -0
  12. package/dist/lib/resources/ActivitiesClient.d.ts +89 -0
  13. package/dist/lib/resources/ActivitiesClient.js +99 -0
  14. package/dist/lib/resources/AgentsClient.d.ts +121 -0
  15. package/dist/lib/resources/AgentsClient.js +134 -0
  16. package/dist/lib/resources/BenchmarkExecutionsClient.d.ts +250 -0
  17. package/dist/lib/resources/BenchmarkExecutionsClient.js +261 -0
  18. package/dist/lib/resources/BenchmarksClient.d.ts +159 -0
  19. package/dist/lib/resources/BenchmarksClient.js +158 -0
  20. package/dist/lib/resources/BoardsClient.d.ts +65 -0
  21. package/dist/lib/resources/BoardsClient.js +74 -0
  22. package/dist/lib/resources/CardsClient.d.ts +161 -0
  23. package/dist/lib/resources/CardsClient.js +202 -0
  24. package/dist/lib/resources/ExternalChannelsClient.d.ts +65 -0
  25. package/dist/lib/resources/ExternalChannelsClient.js +74 -0
  26. package/dist/lib/resources/ResourcesClient.d.ts +92 -0
  27. package/dist/lib/resources/ResourcesClient.js +98 -0
  28. package/dist/lib/resources/SupervisorFeedbackClient.d.ts +75 -0
  29. package/dist/lib/resources/SupervisorFeedbackClient.js +67 -0
  30. package/dist/lib/resources/TeamMembersClient.d.ts +66 -0
  31. package/dist/lib/resources/TeamMembersClient.js +75 -0
  32. package/dist/lib/resources/TeamsClient.d.ts +83 -0
  33. package/dist/lib/resources/TeamsClient.js +92 -0
  34. package/dist/lib/resources/__tests__/ActivitiesClient.test.d.ts +1 -0
  35. package/dist/lib/resources/__tests__/ActivitiesClient.test.js +33 -0
  36. package/dist/lib/resources/__tests__/AgentsClient.test.d.ts +1 -0
  37. package/dist/lib/resources/__tests__/AgentsClient.test.js +37 -0
  38. package/dist/lib/resources/__tests__/BenchmarkExecutionsClient.test.d.ts +1 -0
  39. package/dist/lib/resources/__tests__/BenchmarkExecutionsClient.test.js +59 -0
  40. package/dist/lib/resources/__tests__/BenchmarksClient.test.d.ts +1 -0
  41. package/dist/lib/resources/__tests__/BenchmarksClient.test.js +42 -0
  42. package/dist/lib/resources/__tests__/BoardsClient.test.d.ts +1 -0
  43. package/dist/lib/resources/__tests__/BoardsClient.test.js +26 -0
  44. package/dist/lib/resources/__tests__/CardsClient.test.d.ts +1 -0
  45. package/dist/lib/resources/__tests__/CardsClient.test.js +62 -0
  46. package/dist/lib/resources/__tests__/ExternalChannelsClient.test.d.ts +1 -0
  47. package/dist/lib/resources/__tests__/ExternalChannelsClient.test.js +26 -0
  48. package/dist/lib/resources/__tests__/ResourcesClient.test.d.ts +1 -0
  49. package/dist/lib/resources/__tests__/ResourcesClient.test.js +28 -0
  50. package/dist/lib/resources/__tests__/SupervisorFeedbackClient.test.d.ts +1 -0
  51. package/dist/lib/resources/__tests__/SupervisorFeedbackClient.test.js +24 -0
  52. package/dist/lib/resources/__tests__/TeamMembersClient.test.d.ts +1 -0
  53. package/dist/lib/resources/__tests__/TeamMembersClient.test.js +26 -0
  54. package/dist/lib/resources/__tests__/TeamsClient.test.d.ts +1 -0
  55. package/dist/lib/resources/__tests__/TeamsClient.test.js +26 -0
  56. package/dist/test/helpers/mockFetch.d.ts +8 -0
  57. package/dist/test/helpers/mockFetch.js +22 -0
  58. package/dist/types/a2a-data-parts.d.ts +64 -0
  59. package/dist/types/a2a-data-parts.js +13 -0
  60. package/dist/types/entities/activities.d.ts +32 -0
  61. package/dist/types/entities/activities.js +1 -0
  62. package/dist/types/entities/agent.d.ts +16 -0
  63. package/dist/types/entities/agent.js +1 -0
  64. package/dist/types/entities/benchmark.d.ts +82 -0
  65. package/dist/types/entities/benchmark.js +1 -0
  66. package/dist/types/entities/board.d.ts +20 -0
  67. package/dist/types/entities/board.js +1 -0
  68. package/dist/types/entities/card.d.ts +50 -0
  69. package/dist/types/entities/card.js +1 -0
  70. package/dist/types/entities/external-channel.d.ts +12 -0
  71. package/dist/types/entities/external-channel.js +1 -0
  72. package/dist/types/entities/index.d.ts +9 -0
  73. package/dist/types/entities/index.js +9 -0
  74. package/dist/types/entities/resource.d.ts +16 -0
  75. package/dist/types/entities/resource.js +1 -0
  76. package/dist/types/entities/shared.d.ts +1 -0
  77. package/dist/types/entities/shared.js +2 -0
  78. package/dist/types/entities/team.d.ts +14 -0
  79. package/dist/types/entities/team.js +1 -0
  80. package/dist/types/entities.d.ts +1 -0
  81. package/dist/types/entities.js +1 -0
  82. package/dist/types/requests.d.ts +22 -0
  83. package/dist/types/requests.js +1 -0
  84. package/dist/types/responses.d.ts +77 -0
  85. package/dist/types/responses.js +1 -0
  86. package/package.json +54 -0
package/README.md ADDED
@@ -0,0 +1,225 @@
1
+ # Kaiban TypeScript SDK
2
+
3
+ Official TypeScript SDK for the Kaiban API.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @kaiban-sdk
9
+ ```
10
+
11
+ ## Quickstart
12
+
13
+ ```ts
14
+ import { createKaibanClient } from '@kaiban-sdk';
15
+
16
+ const client = createKaibanClient({
17
+ tenant: 'agi',
18
+ token: process.env.KAIBAN_TOKEN,
19
+ });
20
+
21
+ const agents = await client.agents.list();
22
+ ```
23
+
24
+ ## Auth and tenancy
25
+
26
+ - Uses `Authorization: Bearer <token>` automatically when provided
27
+ - Sends `x-tenant` with the configured tenant
28
+ - Default base URL: `https://{tenant}.kaiban.io`
29
+
30
+ ## Resources
31
+
32
+ - activities: list, create, updateBulk
33
+ - agents: list, get, update, feedback
34
+ - boards: list, get
35
+ - cards: list, get, create, update, delete, moveToColumn
36
+ - external-channels: list, get
37
+ - resources: list, get, publish
38
+ - supervisor-feedback: list by agent
39
+ - teams: list, get
40
+
41
+ ## Types
42
+
43
+ Types are published under the package and re-exported from `@kaiban-sdk` (e.g., `Agent`, `Card`, `BenchmarkExecution`).
44
+
45
+ ## Documentation
46
+
47
+ The SDK includes comprehensive JSDoc documentation for all client methods and types.
48
+
49
+ ### Generate Documentation
50
+
51
+ To generate the full API documentation:
52
+
53
+ ```bash
54
+ npm run docs:generate
55
+ ```
56
+
57
+ This will create a `docs` folder with HTML documentation that you can open in your browser.
58
+
59
+ ### Build Documentation
60
+
61
+ To clean and rebuild the documentation from scratch:
62
+
63
+ ```bash
64
+ npm run docs:build
65
+ ```
66
+
67
+ ### Serve Documentation Locally
68
+
69
+ To generate and serve the documentation locally:
70
+
71
+ ```bash
72
+ npm run docs:serve
73
+ ```
74
+
75
+ This will generate the docs and start a local server (requires `npx serve` to be available).
76
+
77
+ ### Clean Documentation
78
+
79
+ To remove the generated documentation:
80
+
81
+ ```bash
82
+ npm run docs:clean
83
+ ```
84
+
85
+ ## Configuration
86
+
87
+ ```ts
88
+ createKaibanClient({
89
+ tenant: 'agi',
90
+ token: '...optional...',
91
+ baseUrl: 'https://custom-host',
92
+ timeoutMs: 30000,
93
+ });
94
+ ```
95
+
96
+ ## Per-call options
97
+
98
+ All resource methods accept optional per-call overrides:
99
+
100
+ ```ts
101
+ // Headers, query params, timeout override, and AbortSignal
102
+ await client.cards.list({
103
+ headers: { 'x-request-id': 'abc-123' },
104
+ query: { status: 'doing' },
105
+ timeoutMs: 10_000,
106
+ signal: new AbortController().signal,
107
+ });
108
+ ```
109
+
110
+ ## Error handling
111
+
112
+ ```ts
113
+ import { createKaibanClient, HttpError } from '@kaiban-sdk';
114
+
115
+ try {
116
+ await client.cards.get({ id: 'non-existent' });
117
+ } catch (err) {
118
+ if (err instanceof HttpError) {
119
+ console.error('HTTP error', err.status, err.url, err.body);
120
+ } else {
121
+ console.error('Unexpected error', err);
122
+ }
123
+ }
124
+ ```
125
+
126
+ ## Examples by resource
127
+
128
+ ### Agents
129
+
130
+ ```ts
131
+ // List agents
132
+ const agents = await client.agents.list();
133
+
134
+ // Get agent by id
135
+ const agent = await client.agents.get({ id: 'agent_123' });
136
+
137
+ // Update agent
138
+ const updated = await client.agents.update({ id: 'agent_123', body: { description: 'New desc' } });
139
+
140
+ // Create agent feedback
141
+ await client.agents.createFeedback({ id: 'agent_123', feedback: { rating: 5, comment: 'Great' } });
142
+ ```
143
+
144
+ ### Teams
145
+
146
+ ```ts
147
+ const teams = await client.teams.list();
148
+ const team = await client.teams.get({ id: 'team_123' });
149
+ ```
150
+
151
+ ### Boards
152
+
153
+ ```ts
154
+ const boards = await client.boards.list();
155
+ const board = await client.boards.get({ id: 'board_123' });
156
+ ```
157
+
158
+ ### Cards
159
+
160
+ ```ts
161
+ import type { CreateCardInput, UpdateCardInput } from '@kaiban-sdk';
162
+
163
+ // Create a card
164
+ const createBody: CreateCardInput = {
165
+ team_id: 'team_123',
166
+ board_id: 'board_123',
167
+ owner_id: 'user_123',
168
+ agent_id: 'agent_123',
169
+ title: 'Investigate issue',
170
+ status: 'backlog',
171
+ column_key: 'inbox',
172
+ priority: 'medium',
173
+ member_ids: [],
174
+ };
175
+ const newCard = await client.cards.create({ body: createBody });
176
+
177
+ // Get a card
178
+ const card = await client.cards.get({ id: newCard.id });
179
+
180
+ // Update a card
181
+ const updateBody: UpdateCardInput = { status: 'doing', priority: 'high' };
182
+ const updatedCard = await client.cards.update({ id: card.id, body: updateBody });
183
+
184
+ // List cards
185
+ const cards = await client.cards.list();
186
+
187
+ // Delete a card
188
+ await client.cards.delete({ id: card.id });
189
+
190
+ // Activities
191
+ const activities = await client.activities.list({ card_id: card.id });
192
+ await client.activities.create({
193
+ card_id: card.id,
194
+ body: {
195
+ board_id: card.board_id,
196
+ team_id: card.team_id,
197
+ card_id: card.id,
198
+ type: 'card_comment_added',
199
+ description: 'FYI',
200
+ actor: { id: 'user_1', type: 'user', name: 'Alice' },
201
+ },
202
+ });
203
+ await client.activities.updateBulk({ card_id: card.id, body: activities });
204
+ ```
205
+
206
+ ### Resources
207
+
208
+ ```ts
209
+ const resources = await client.resources.list();
210
+ const resource = await client.resources.get({ id: 'resource_123' });
211
+ await client.resources.publish({ resource_id: 'resource_123', userId: 'user_123' });
212
+ ```
213
+
214
+ ### External Channels
215
+
216
+ ```ts
217
+ const channels = await client.externalChannels.list();
218
+ const channel = await client.externalChannels.get({ id: 'ext_123' });
219
+ ```
220
+
221
+ ### Supervisor Feedback
222
+
223
+ ```ts
224
+ const feedback = await client.supervisorFeedback.listByAgent({ agent_id: 'agent_123' });
225
+ ```
@@ -0,0 +1,15 @@
1
+ export * from './lib/client';
2
+ export * from './lib/http/errors';
3
+ export * from './lib/resources/AgentsClient';
4
+ export * from './lib/resources/CardsClient';
5
+ export * from './lib/resources/ActivitiesClient';
6
+ export * from './lib/resources/TeamsClient';
7
+ export * from './lib/resources/BoardsClient';
8
+ export * from './lib/resources/ResourcesClient';
9
+ export * from './lib/resources/ExternalChannelsClient';
10
+ export * from './lib/resources/SupervisorFeedbackClient';
11
+ export * from './lib/http/types';
12
+ export * from './types/entities';
13
+ export * from './types/requests';
14
+ export * from './types/responses';
15
+ export * from './types/a2a-data-parts';
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ export * from './lib/client';
2
+ export * from './lib/http/errors';
3
+ export * from './lib/resources/AgentsClient';
4
+ export * from './lib/resources/CardsClient';
5
+ export * from './lib/resources/ActivitiesClient';
6
+ export * from './lib/resources/TeamsClient';
7
+ export * from './lib/resources/BoardsClient';
8
+ export * from './lib/resources/ResourcesClient';
9
+ export * from './lib/resources/ExternalChannelsClient';
10
+ export * from './lib/resources/SupervisorFeedbackClient';
11
+ export * from './lib/http/types';
12
+ export * from './types/entities';
13
+ export * from './types/requests';
14
+ export * from './types/responses';
15
+ export * from './types/a2a-data-parts';
@@ -0,0 +1,65 @@
1
+ import { KaibanClientConfig } from './http/types';
2
+ import { AgentsClient } from './resources/AgentsClient';
3
+ import { CardsClient } from './resources/CardsClient';
4
+ import { TeamsClient } from './resources/TeamsClient';
5
+ import { BoardsClient } from './resources/BoardsClient';
6
+ import { ResourcesClient } from './resources/ResourcesClient';
7
+ import { ExternalChannelsClient } from './resources/ExternalChannelsClient';
8
+ import { SupervisorFeedbackClient } from './resources/SupervisorFeedbackClient';
9
+ import { ActivitiesClient } from './resources/ActivitiesClient';
10
+ /**
11
+ * Main Kaiban SDK client interface providing access to all API resources
12
+ * @category Client
13
+ */
14
+ export interface KaibanClient {
15
+ /**
16
+ * Set or clear the bearer token used for authorization
17
+ * @param token - Optional bearer token. If omitted, clears the current token
18
+ */
19
+ setToken: (token?: string) => void;
20
+ /** Client for managing agents */
21
+ agents: AgentsClient;
22
+ /** Client for managing cards */
23
+ cards: CardsClient;
24
+ /** Client for managing card activities */
25
+ activities: ActivitiesClient;
26
+ /** Client for managing teams */
27
+ teams: TeamsClient;
28
+ /** Client for managing boards */
29
+ boards: BoardsClient;
30
+ /** Client for managing resources */
31
+ resources: ResourcesClient;
32
+ /** Client for managing external channels */
33
+ externalChannels: ExternalChannelsClient;
34
+ /** Client for managing supervisor feedback */
35
+ supervisorFeedback: SupervisorFeedbackClient;
36
+ }
37
+ /**
38
+ * Create a Kaiban SDK client instance
39
+ *
40
+ * @param config - Client configuration object
41
+ * @param config.tenant - The tenant identifier for your Kaiban instance
42
+ * @param config.token - Optional bearer token for authentication
43
+ * @param config.baseUrl - Optional custom base URL for the API
44
+ * @param config.maxRetries - Optional maximum number of request retries (default: 3)
45
+ * @param config.timeout - Optional request timeout in milliseconds (default: 30000)
46
+ *
47
+ * @returns A configured Kaiban client instance
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * import { createKaibanClient } from 'kaiban-sdk';
52
+ *
53
+ * const client = createKaibanClient({
54
+ * tenant: 'my-tenant',
55
+ * token: 'my-auth-token',
56
+ * baseUrl: 'https://api.kaiban.ai'
57
+ * });
58
+ *
59
+ * // List all agents
60
+ * const agents = await client.agents.list();
61
+ * ```
62
+ *
63
+ * @category Client
64
+ */
65
+ export declare function createKaibanClient(config: KaibanClientConfig): KaibanClient;
@@ -0,0 +1,51 @@
1
+ import { HttpClient } from './http/HttpClient';
2
+ import { AgentsClient } from './resources/AgentsClient';
3
+ import { CardsClient } from './resources/CardsClient';
4
+ import { TeamsClient } from './resources/TeamsClient';
5
+ import { BoardsClient } from './resources/BoardsClient';
6
+ import { ResourcesClient } from './resources/ResourcesClient';
7
+ import { ExternalChannelsClient } from './resources/ExternalChannelsClient';
8
+ import { SupervisorFeedbackClient } from './resources/SupervisorFeedbackClient';
9
+ import { ActivitiesClient } from './resources/ActivitiesClient';
10
+ /**
11
+ * Create a Kaiban SDK client instance
12
+ *
13
+ * @param config - Client configuration object
14
+ * @param config.tenant - The tenant identifier for your Kaiban instance
15
+ * @param config.token - Optional bearer token for authentication
16
+ * @param config.baseUrl - Optional custom base URL for the API
17
+ * @param config.maxRetries - Optional maximum number of request retries (default: 3)
18
+ * @param config.timeout - Optional request timeout in milliseconds (default: 30000)
19
+ *
20
+ * @returns A configured Kaiban client instance
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * import { createKaibanClient } from 'kaiban-sdk';
25
+ *
26
+ * const client = createKaibanClient({
27
+ * tenant: 'my-tenant',
28
+ * token: 'my-auth-token',
29
+ * baseUrl: 'https://api.kaiban.ai'
30
+ * });
31
+ *
32
+ * // List all agents
33
+ * const agents = await client.agents.list();
34
+ * ```
35
+ *
36
+ * @category Client
37
+ */
38
+ export function createKaibanClient(config) {
39
+ const http = new HttpClient(config);
40
+ return {
41
+ setToken: (t) => http.setToken(t),
42
+ agents: new AgentsClient(http),
43
+ cards: new CardsClient(http),
44
+ activities: new ActivitiesClient(http),
45
+ teams: new TeamsClient(http),
46
+ boards: new BoardsClient(http),
47
+ resources: new ResourcesClient(http),
48
+ externalChannels: new ExternalChannelsClient(http),
49
+ supervisorFeedback: new SupervisorFeedbackClient(http),
50
+ };
51
+ }
@@ -0,0 +1,16 @@
1
+ import { ListParams } from '../../types/responses';
2
+ import { KaibanClientConfig, RequestOptions } from './types';
3
+ export declare class HttpClient {
4
+ private config;
5
+ private _token?;
6
+ private retryCfg;
7
+ constructor(config: KaibanClientConfig);
8
+ setToken(token?: string): void;
9
+ private attempt;
10
+ private request;
11
+ get<T>(path: string, options?: RequestOptions): Promise<T>;
12
+ post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
13
+ put<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
14
+ delete<T>(path: string, options?: RequestOptions): Promise<T>;
15
+ list<T>(path: string, listParams?: ListParams, options?: RequestOptions): Promise<T>;
16
+ }
@@ -0,0 +1,237 @@
1
+ import { TimeoutError, AbortedError, RateLimitError, UnavailableError, ServerError, mapHttpToSdkError, } from './errors';
2
+ function buildQuery(query) {
3
+ if (!query)
4
+ return '';
5
+ const params = new URLSearchParams();
6
+ for (const [k, v] of Object.entries(query)) {
7
+ if (v !== undefined && v !== null)
8
+ params.append(k, String(v));
9
+ }
10
+ const qs = params.toString();
11
+ return qs ? `?${qs}` : '';
12
+ }
13
+ function sleep(ms) {
14
+ return new Promise((r) => setTimeout(r, ms));
15
+ }
16
+ export class HttpClient {
17
+ constructor(config) {
18
+ const defaultRetry = {
19
+ maxAttempts: 3,
20
+ backoffMs: 250,
21
+ maxBackoffMs: 4000,
22
+ jitter: true,
23
+ retryOn: [429, 500, 502, 503, 504],
24
+ retryMethods: ['GET', 'PUT', 'DELETE'],
25
+ };
26
+ const baseUrl = config.baseUrl || `https://${config.tenant}.kaiban.io`;
27
+ this.config = {
28
+ tenant: config.tenant,
29
+ token: config.token,
30
+ baseUrl,
31
+ timeoutMs: config.timeoutMs ?? 30000,
32
+ retry: {
33
+ ...defaultRetry,
34
+ ...(config.retry || {}),
35
+ retryOn: [
36
+ ...(Array.isArray((config.retry || {}).retryOn)
37
+ ? (config.retry || {}).retryOn
38
+ : defaultRetry.retryOn),
39
+ ],
40
+ retryMethods: [
41
+ ...(Array.isArray((config.retry || {}).retryMethods)
42
+ ? (config.retry || {}).retryMethods
43
+ : defaultRetry.retryMethods),
44
+ ],
45
+ },
46
+ fetch: config.fetch || fetch,
47
+ onRequest: config.onRequest || (() => { }),
48
+ onResponse: config.onResponse || (() => { }),
49
+ };
50
+ this._token = config.token;
51
+ // Normalize retry config with required fields for internal use
52
+ const r = this.config.retry;
53
+ this.retryCfg = {
54
+ maxAttempts: r.maxAttempts ?? defaultRetry.maxAttempts,
55
+ backoffMs: r.backoffMs ?? defaultRetry.backoffMs,
56
+ maxBackoffMs: r.maxBackoffMs ?? defaultRetry.maxBackoffMs,
57
+ jitter: r.jitter ?? defaultRetry.jitter,
58
+ retryOn: Array.isArray(r.retryOn) ? r.retryOn : defaultRetry.retryOn,
59
+ retryMethods: Array.isArray(r.retryMethods) ? r.retryMethods : defaultRetry.retryMethods,
60
+ };
61
+ }
62
+ setToken(token) {
63
+ this._token = token;
64
+ }
65
+ async attempt(fn, retryCfg) {
66
+ const { maxAttempts = 3, backoffMs = 250, maxBackoffMs = 4000, jitter = true } = retryCfg;
67
+ let attempt = 0;
68
+ let delay = backoffMs;
69
+ while (true) {
70
+ try {
71
+ return await fn();
72
+ }
73
+ catch (err) {
74
+ attempt++;
75
+ if (attempt >= maxAttempts)
76
+ throw err;
77
+ const wait = jitter ? Math.min(maxBackoffMs, delay * (1 + Math.random())) : delay;
78
+ await sleep(wait);
79
+ delay = Math.min(maxBackoffMs, delay * 2);
80
+ }
81
+ }
82
+ }
83
+ async request(method, path, body, options) {
84
+ const normalizedPath = path.startsWith('/v1') ? path : `/v1${path}`;
85
+ const url = `${this.config.baseUrl}${normalizedPath}${buildQuery(options?.query)}`;
86
+ const headers = {
87
+ 'content-type': 'application/json',
88
+ 'x-tenant': this.config.tenant,
89
+ ...(this._token ? { authorization: `Bearer ${this._token}` } : {}),
90
+ ...(options?.headers || {}),
91
+ };
92
+ // Compose abort signals: user-provided and timeout
93
+ const combinedController = new AbortController();
94
+ const userSignal = options?.signal;
95
+ let timedOut = false;
96
+ const timeout = setTimeout(() => {
97
+ timedOut = true;
98
+ combinedController.abort();
99
+ }, options?.timeoutMs ?? this.config.timeoutMs);
100
+ const onUserAbort = () => combinedController.abort();
101
+ if (userSignal) {
102
+ if (userSignal.aborted) {
103
+ // propagate immediately
104
+ combinedController.abort();
105
+ }
106
+ else {
107
+ userSignal.addEventListener('abort', onUserAbort);
108
+ }
109
+ }
110
+ const init = {
111
+ method,
112
+ headers,
113
+ body: body !== undefined ? JSON.stringify(body) : undefined,
114
+ signal: combinedController.signal,
115
+ };
116
+ this.config.onRequest({ method, url, init });
117
+ const doFetch = async () => {
118
+ try {
119
+ const res = await this.config.fetch(url, init);
120
+ this.config.onResponse({ status: res.status, url, response: res });
121
+ let parsed;
122
+ const contentType = res.headers.get('content-type') || '';
123
+ if (contentType.includes('application/json')) {
124
+ try {
125
+ parsed = await res.json();
126
+ }
127
+ catch {
128
+ parsed = undefined;
129
+ }
130
+ }
131
+ else {
132
+ parsed = await res.text();
133
+ }
134
+ if (!res.ok) {
135
+ throw mapHttpToSdkError(res.status, parsed);
136
+ }
137
+ return parsed;
138
+ }
139
+ catch (e) {
140
+ if (isAbortError(e)) {
141
+ if (timedOut)
142
+ throw new TimeoutError();
143
+ throw new AbortedError();
144
+ }
145
+ throw e;
146
+ }
147
+ finally {
148
+ clearTimeout(timeout);
149
+ if (userSignal)
150
+ userSignal.removeEventListener('abort', onUserAbort);
151
+ }
152
+ };
153
+ const retryCfg = mergeRetryConfig(this.retryCfg, options?.retry);
154
+ const shouldRetry = (err) => {
155
+ const methodUpper = method.toUpperCase();
156
+ const retryableByMethod = retryCfg.retryMethods?.includes(methodUpper);
157
+ if (!retryableByMethod)
158
+ return false;
159
+ if (err instanceof TimeoutError)
160
+ return true;
161
+ // Retry on known transient SDK errors
162
+ if (err instanceof RateLimitError)
163
+ return retryCfg.retryOn?.includes(429) ?? false;
164
+ if (err instanceof UnavailableError)
165
+ return retryCfg.retryOn?.some((c) => c === 502 || c === 503 || c === 504) ?? false;
166
+ if (err instanceof ServerError)
167
+ return retryCfg.retryOn?.includes(500) ?? false;
168
+ return false;
169
+ };
170
+ return await this.attempt(async () => {
171
+ try {
172
+ return await doFetch();
173
+ }
174
+ catch (err) {
175
+ if (shouldRetry(err))
176
+ throw err;
177
+ throw err;
178
+ }
179
+ }, retryCfg);
180
+ }
181
+ get(path, options) {
182
+ return this.request('GET', path, undefined, options);
183
+ }
184
+ post(path, body, options) {
185
+ return this.request('POST', path, body, options);
186
+ }
187
+ put(path, body, options) {
188
+ return this.request('PUT', path, body, options);
189
+ }
190
+ delete(path, options) {
191
+ return this.request('DELETE', path, undefined, options);
192
+ }
193
+ list(path, listParams, options) {
194
+ const queryParams = {};
195
+ if (listParams) {
196
+ // Handle pagination
197
+ if (listParams.cursor)
198
+ queryParams.cursor = listParams.cursor;
199
+ if (listParams.limit)
200
+ queryParams.limit = listParams.limit;
201
+ // Handle sorting (already a string)
202
+ if (listParams.order_by)
203
+ queryParams.order_by = listParams.order_by;
204
+ // Handle filters
205
+ if (listParams.filters) {
206
+ Object.entries(listParams.filters).forEach(([key, value]) => {
207
+ queryParams[key] = value;
208
+ });
209
+ }
210
+ // Handle metadata filters for cards
211
+ if (listParams.metadata) {
212
+ Object.entries(listParams.metadata).forEach(([key, value]) => {
213
+ queryParams[`metadata.${key}`] = value;
214
+ });
215
+ }
216
+ }
217
+ return this.request('GET', path, undefined, { ...options, query: queryParams });
218
+ }
219
+ }
220
+ function isAbortError(e) {
221
+ if (!e)
222
+ return false;
223
+ const anyErr = e;
224
+ return anyErr && anyErr.name === 'AbortError';
225
+ }
226
+ function mergeRetryConfig(base, override) {
227
+ if (!override)
228
+ return base;
229
+ return {
230
+ maxAttempts: override.maxAttempts ?? base.maxAttempts,
231
+ backoffMs: override.backoffMs ?? base.backoffMs,
232
+ maxBackoffMs: override.maxBackoffMs ?? base.maxBackoffMs,
233
+ jitter: override.jitter ?? base.jitter,
234
+ retryOn: override.retryOn ? [...override.retryOn] : base.retryOn,
235
+ retryMethods: override.retryMethods ? [...override.retryMethods] : base.retryMethods,
236
+ };
237
+ }
@@ -0,0 +1,50 @@
1
+ export declare class HttpError extends Error {
2
+ readonly status: number;
3
+ readonly url: string;
4
+ readonly body?: unknown;
5
+ constructor(message: string, status: number, url: string, body?: unknown);
6
+ }
7
+ export declare class TimeoutError extends Error {
8
+ constructor(message?: string);
9
+ }
10
+ export declare class AbortedError extends Error {
11
+ constructor(message?: string);
12
+ }
13
+ export interface ApiErrorShape {
14
+ code?: string;
15
+ message: string;
16
+ details?: unknown;
17
+ }
18
+ export declare class ApiError extends Error {
19
+ readonly code?: string;
20
+ readonly details?: unknown;
21
+ constructor(shape: ApiErrorShape);
22
+ }
23
+ export declare class BadRequestError extends ApiError {
24
+ constructor(shape: ApiErrorShape);
25
+ }
26
+ export declare class ValidationError extends ApiError {
27
+ constructor(shape: ApiErrorShape);
28
+ }
29
+ export declare class UnauthorizedError extends ApiError {
30
+ constructor(shape: ApiErrorShape);
31
+ }
32
+ export declare class ForbiddenError extends ApiError {
33
+ constructor(shape: ApiErrorShape);
34
+ }
35
+ export declare class NotFoundError extends ApiError {
36
+ constructor(shape: ApiErrorShape);
37
+ }
38
+ export declare class ConflictError extends ApiError {
39
+ constructor(shape: ApiErrorShape);
40
+ }
41
+ export declare class RateLimitError extends ApiError {
42
+ constructor(shape: ApiErrorShape);
43
+ }
44
+ export declare class UnavailableError extends ApiError {
45
+ constructor(shape: ApiErrorShape);
46
+ }
47
+ export declare class ServerError extends ApiError {
48
+ constructor(shape: ApiErrorShape);
49
+ }
50
+ export declare function mapHttpToSdkError(status: number, body: unknown): ApiError;