@dispatchtickets/sdk 0.1.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -9
- package/dist/index.cjs +509 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +780 -20
- package/dist/index.d.ts +780 -20
- package/dist/index.js +497 -68
- package/dist/index.js.map +1 -1
- package/package.json +10 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom fetch function type
|
|
3
|
+
*/
|
|
4
|
+
type FetchFunction = typeof fetch;
|
|
5
|
+
/**
|
|
6
|
+
* Request context passed to hooks
|
|
7
|
+
*/
|
|
8
|
+
interface RequestContext {
|
|
9
|
+
/** HTTP method */
|
|
10
|
+
method: string;
|
|
11
|
+
/** Full URL being requested */
|
|
12
|
+
url: string;
|
|
13
|
+
/** Request headers */
|
|
14
|
+
headers: Record<string, string>;
|
|
15
|
+
/** Request body (if any) */
|
|
16
|
+
body?: unknown;
|
|
17
|
+
/** Retry attempt number (0 = first attempt) */
|
|
18
|
+
attempt: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Response context passed to hooks
|
|
22
|
+
*/
|
|
23
|
+
interface ResponseContext {
|
|
24
|
+
/** The request that was made */
|
|
25
|
+
request: RequestContext;
|
|
26
|
+
/** HTTP status code */
|
|
27
|
+
status: number;
|
|
28
|
+
/** Response headers */
|
|
29
|
+
headers: Headers;
|
|
30
|
+
/** Request ID from server */
|
|
31
|
+
requestId?: string;
|
|
32
|
+
/** Rate limit info from server */
|
|
33
|
+
rateLimit?: RateLimitInfo;
|
|
34
|
+
/** Duration of the request in milliseconds */
|
|
35
|
+
durationMs: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Retry configuration options
|
|
39
|
+
*/
|
|
40
|
+
interface RetryConfig {
|
|
41
|
+
/**
|
|
42
|
+
* Maximum number of retry attempts
|
|
43
|
+
* @default 3
|
|
44
|
+
*/
|
|
45
|
+
maxRetries?: number;
|
|
46
|
+
/**
|
|
47
|
+
* HTTP status codes that should trigger a retry
|
|
48
|
+
* @default [429, 500, 502, 503, 504]
|
|
49
|
+
*/
|
|
50
|
+
retryableStatuses?: number[];
|
|
51
|
+
/**
|
|
52
|
+
* Whether to retry on network errors
|
|
53
|
+
* @default true
|
|
54
|
+
*/
|
|
55
|
+
retryOnNetworkError?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Whether to retry on timeout errors
|
|
58
|
+
* @default true
|
|
59
|
+
*/
|
|
60
|
+
retryOnTimeout?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Initial delay between retries in milliseconds
|
|
63
|
+
* @default 1000
|
|
64
|
+
*/
|
|
65
|
+
initialDelayMs?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Maximum delay between retries in milliseconds
|
|
68
|
+
* @default 30000
|
|
69
|
+
*/
|
|
70
|
+
maxDelayMs?: number;
|
|
71
|
+
/**
|
|
72
|
+
* Multiplier for exponential backoff
|
|
73
|
+
* @default 2
|
|
74
|
+
*/
|
|
75
|
+
backoffMultiplier?: number;
|
|
76
|
+
/**
|
|
77
|
+
* Jitter factor (0-1) to add randomness to delays
|
|
78
|
+
* @default 0.25
|
|
79
|
+
*/
|
|
80
|
+
jitter?: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Hooks for observability and customization
|
|
84
|
+
*/
|
|
85
|
+
interface Hooks {
|
|
86
|
+
/**
|
|
87
|
+
* Called before each request is sent
|
|
88
|
+
* Can modify the request or throw to abort
|
|
89
|
+
*/
|
|
90
|
+
onRequest?: (context: RequestContext) => void | Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Called after each successful response
|
|
93
|
+
*/
|
|
94
|
+
onResponse?: (context: ResponseContext) => void | Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Called when an error occurs (before retry)
|
|
97
|
+
*/
|
|
98
|
+
onError?: (error: Error, context: RequestContext) => void | Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Called before each retry attempt
|
|
101
|
+
*/
|
|
102
|
+
onRetry?: (context: RequestContext, error: Error, delayMs: number) => void | Promise<void>;
|
|
103
|
+
}
|
|
1
104
|
interface HttpClientConfig {
|
|
2
105
|
baseUrl: string;
|
|
3
106
|
apiKey: string;
|
|
4
107
|
timeout: number;
|
|
5
108
|
maxRetries: number;
|
|
6
109
|
debug?: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Custom fetch implementation for testing/mocking
|
|
112
|
+
*/
|
|
113
|
+
fetch?: FetchFunction;
|
|
114
|
+
/**
|
|
115
|
+
* Fine-grained retry configuration
|
|
116
|
+
*/
|
|
117
|
+
retry?: RetryConfig;
|
|
118
|
+
/**
|
|
119
|
+
* Hooks for observability
|
|
120
|
+
*/
|
|
121
|
+
hooks?: Hooks;
|
|
7
122
|
}
|
|
8
123
|
interface RequestOptions {
|
|
9
124
|
method: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
|
@@ -12,39 +127,201 @@ interface RequestOptions {
|
|
|
12
127
|
query?: Record<string, string | number | boolean | undefined>;
|
|
13
128
|
headers?: Record<string, string>;
|
|
14
129
|
idempotencyKey?: string;
|
|
130
|
+
/**
|
|
131
|
+
* AbortSignal to cancel the request
|
|
132
|
+
*/
|
|
133
|
+
signal?: AbortSignal;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Rate limit information from response headers
|
|
137
|
+
*/
|
|
138
|
+
interface RateLimitInfo {
|
|
139
|
+
/** Maximum requests allowed in the current window */
|
|
140
|
+
limit: number;
|
|
141
|
+
/** Remaining requests in the current window */
|
|
142
|
+
remaining: number;
|
|
143
|
+
/** Unix timestamp (seconds) when the rate limit resets */
|
|
144
|
+
reset: number;
|
|
15
145
|
}
|
|
16
146
|
/**
|
|
17
|
-
*
|
|
147
|
+
* Response wrapper with rate limit info
|
|
148
|
+
*/
|
|
149
|
+
interface ResponseWithRateLimit<T> {
|
|
150
|
+
data: T;
|
|
151
|
+
rateLimit?: RateLimitInfo;
|
|
152
|
+
requestId?: string;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* HTTP client with retry logic, hooks, and error handling
|
|
18
156
|
*/
|
|
19
157
|
declare class HttpClient {
|
|
20
158
|
private readonly config;
|
|
159
|
+
private readonly fetchFn;
|
|
160
|
+
private readonly retryConfig;
|
|
161
|
+
/** Rate limit info from the last response */
|
|
162
|
+
private _lastRateLimit?;
|
|
163
|
+
/** Request ID from the last response */
|
|
164
|
+
private _lastRequestId?;
|
|
21
165
|
constructor(config: HttpClientConfig);
|
|
166
|
+
/**
|
|
167
|
+
* Get rate limit info from the last response
|
|
168
|
+
*/
|
|
169
|
+
get lastRateLimit(): RateLimitInfo | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* Get request ID from the last response
|
|
172
|
+
*/
|
|
173
|
+
get lastRequestId(): string | undefined;
|
|
22
174
|
/**
|
|
23
175
|
* Execute an HTTP request with retry logic
|
|
24
176
|
*/
|
|
25
177
|
request<T>(options: RequestOptions): Promise<T>;
|
|
178
|
+
/**
|
|
179
|
+
* Execute request and return response with rate limit info
|
|
180
|
+
*/
|
|
181
|
+
requestWithRateLimit<T>(options: RequestOptions): Promise<ResponseWithRateLimit<T>>;
|
|
182
|
+
private shouldRetry;
|
|
183
|
+
private calculateDelay;
|
|
26
184
|
private buildUrl;
|
|
27
185
|
private buildHeaders;
|
|
28
186
|
private executeRequest;
|
|
187
|
+
private extractRateLimitInfo;
|
|
29
188
|
private handleResponse;
|
|
30
|
-
private calculateBackoff;
|
|
31
189
|
private sleep;
|
|
32
190
|
}
|
|
33
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Options for API requests
|
|
194
|
+
*/
|
|
195
|
+
interface ApiRequestOptions {
|
|
196
|
+
/**
|
|
197
|
+
* AbortSignal to cancel the request
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* const controller = new AbortController();
|
|
202
|
+
* setTimeout(() => controller.abort(), 5000);
|
|
203
|
+
*
|
|
204
|
+
* const ticket = await client.tickets.get('ws_abc', 'tkt_xyz', {
|
|
205
|
+
* signal: controller.signal,
|
|
206
|
+
* });
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
signal?: AbortSignal;
|
|
210
|
+
}
|
|
34
211
|
/**
|
|
35
212
|
* Base class for all resource classes
|
|
213
|
+
* @internal
|
|
36
214
|
*/
|
|
37
215
|
declare abstract class BaseResource {
|
|
38
216
|
protected readonly http: HttpClient;
|
|
39
217
|
constructor(http: HttpClient);
|
|
40
|
-
protected _get<T>(path: string, query?: RequestOptions['query']): Promise<T>;
|
|
218
|
+
protected _get<T>(path: string, query?: RequestOptions['query'], options?: ApiRequestOptions): Promise<T>;
|
|
41
219
|
protected _post<T>(path: string, body?: unknown, options?: {
|
|
42
220
|
idempotencyKey?: string;
|
|
43
221
|
query?: RequestOptions['query'];
|
|
222
|
+
signal?: AbortSignal;
|
|
44
223
|
}): Promise<T>;
|
|
45
|
-
protected _patch<T>(path: string, body?: unknown): Promise<T>;
|
|
46
|
-
protected _put<T>(path: string, body?: unknown): Promise<T>;
|
|
47
|
-
protected _delete<T>(path: string, query?: RequestOptions['query']): Promise<T>;
|
|
224
|
+
protected _patch<T>(path: string, body?: unknown, options?: ApiRequestOptions): Promise<T>;
|
|
225
|
+
protected _put<T>(path: string, body?: unknown, options?: ApiRequestOptions): Promise<T>;
|
|
226
|
+
protected _delete<T>(path: string, query?: RequestOptions['query'], options?: ApiRequestOptions): Promise<T>;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Account represents the organization/company using Dispatch Tickets
|
|
231
|
+
*/
|
|
232
|
+
interface Account {
|
|
233
|
+
id: string;
|
|
234
|
+
stackbeCustomerId: string;
|
|
235
|
+
stackbeOrganizationId: string;
|
|
236
|
+
createdAt: string;
|
|
237
|
+
updatedAt: string;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Usage statistics for the account
|
|
241
|
+
*/
|
|
242
|
+
interface AccountUsage {
|
|
243
|
+
ticketsThisMonth: number;
|
|
244
|
+
ticketsTotal: number;
|
|
245
|
+
brandsCount: number;
|
|
246
|
+
plan?: {
|
|
247
|
+
name: string;
|
|
248
|
+
ticketLimit: number;
|
|
249
|
+
brandLimit: number | null;
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* API key for programmatic access
|
|
254
|
+
*/
|
|
255
|
+
interface ApiKey {
|
|
256
|
+
id: string;
|
|
257
|
+
name: string;
|
|
258
|
+
keyPreview: string;
|
|
259
|
+
allBrands: boolean;
|
|
260
|
+
brandIds: string[];
|
|
261
|
+
lastUsedAt: string | null;
|
|
262
|
+
createdAt: string;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* API key with the full key value (only returned on creation)
|
|
266
|
+
*/
|
|
267
|
+
interface ApiKeyWithSecret extends ApiKey {
|
|
268
|
+
key: string;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Input for creating an API key
|
|
272
|
+
*/
|
|
273
|
+
interface CreateApiKeyInput {
|
|
274
|
+
name: string;
|
|
275
|
+
/**
|
|
276
|
+
* If true, the API key can access all brands (current and future)
|
|
277
|
+
*/
|
|
278
|
+
allBrands?: boolean;
|
|
279
|
+
/**
|
|
280
|
+
* Specific brand IDs this key can access (ignored if allBrands is true)
|
|
281
|
+
*/
|
|
282
|
+
brandIds?: string[];
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Input for updating API key scope
|
|
286
|
+
*/
|
|
287
|
+
interface UpdateApiKeyScopeInput {
|
|
288
|
+
allBrands?: boolean;
|
|
289
|
+
brandIds?: string[];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Accounts resource for managing the current account
|
|
294
|
+
*/
|
|
295
|
+
declare class AccountsResource extends BaseResource {
|
|
296
|
+
/**
|
|
297
|
+
* Get the current account
|
|
298
|
+
*/
|
|
299
|
+
me(): Promise<Account>;
|
|
300
|
+
/**
|
|
301
|
+
* Get usage statistics for the current account
|
|
302
|
+
*/
|
|
303
|
+
getUsage(): Promise<AccountUsage>;
|
|
304
|
+
/**
|
|
305
|
+
* List all API keys for the current account
|
|
306
|
+
*/
|
|
307
|
+
listApiKeys(): Promise<ApiKey[]>;
|
|
308
|
+
/**
|
|
309
|
+
* Create a new API key
|
|
310
|
+
*
|
|
311
|
+
* Note: The full key value is only returned once on creation.
|
|
312
|
+
* Store it securely as it cannot be retrieved again.
|
|
313
|
+
*/
|
|
314
|
+
createApiKey(data: CreateApiKeyInput): Promise<ApiKeyWithSecret>;
|
|
315
|
+
/**
|
|
316
|
+
* Update the brand scope for an API key
|
|
317
|
+
*/
|
|
318
|
+
updateApiKeyScope(keyId: string, data: UpdateApiKeyScopeInput): Promise<{
|
|
319
|
+
success: boolean;
|
|
320
|
+
}>;
|
|
321
|
+
/**
|
|
322
|
+
* Revoke an API key
|
|
323
|
+
*/
|
|
324
|
+
revokeApiKey(keyId: string): Promise<void>;
|
|
48
325
|
}
|
|
49
326
|
|
|
50
327
|
/**
|
|
@@ -144,6 +421,26 @@ declare class BrandsResource extends BaseResource {
|
|
|
144
421
|
* Update the ticket schema for a brand
|
|
145
422
|
*/
|
|
146
423
|
updateSchema(brandId: string, schema: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
424
|
+
/**
|
|
425
|
+
* Get the inbound email address for a brand
|
|
426
|
+
*
|
|
427
|
+
* Emails sent to this address will automatically create tickets.
|
|
428
|
+
*
|
|
429
|
+
* @param brandId - The brand ID
|
|
430
|
+
* @param domain - Optional custom inbound domain (default: inbound.dispatchtickets.com)
|
|
431
|
+
* @returns The inbound email address
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* ```typescript
|
|
435
|
+
* const email = client.brands.getInboundEmail('br_abc123');
|
|
436
|
+
* // Returns: br_abc123@inbound.dispatchtickets.com
|
|
437
|
+
*
|
|
438
|
+
* // With custom domain:
|
|
439
|
+
* const customEmail = client.brands.getInboundEmail('br_abc123', 'support.mycompany.com');
|
|
440
|
+
* // Returns: br_abc123@support.mycompany.com
|
|
441
|
+
* ```
|
|
442
|
+
*/
|
|
443
|
+
getInboundEmail(brandId: string, domain?: string): string;
|
|
147
444
|
}
|
|
148
445
|
|
|
149
446
|
/**
|
|
@@ -185,9 +482,10 @@ type AuthorType = 'CUSTOMER' | 'AGENT' | 'SYSTEM';
|
|
|
185
482
|
*/
|
|
186
483
|
type AttachmentStatus = 'PENDING' | 'UPLOADED' | 'FAILED';
|
|
187
484
|
/**
|
|
188
|
-
* Webhook event
|
|
485
|
+
* Webhook event type strings (for subscription)
|
|
486
|
+
* @deprecated Use WebhookEventType from events.ts for typed event handling
|
|
189
487
|
*/
|
|
190
|
-
type
|
|
488
|
+
type WebhookEventName = 'ticket.created' | 'ticket.updated' | 'ticket.deleted' | 'ticket.comment.created' | 'comment.created' | 'comment.updated' | 'comment.deleted' | 'attachment.created' | 'attachment.deleted';
|
|
191
489
|
/**
|
|
192
490
|
* Custom field types
|
|
193
491
|
*/
|
|
@@ -655,7 +953,7 @@ interface Webhook {
|
|
|
655
953
|
id: string;
|
|
656
954
|
brandId: string;
|
|
657
955
|
url: string;
|
|
658
|
-
events:
|
|
956
|
+
events: WebhookEventName[];
|
|
659
957
|
enabled: boolean;
|
|
660
958
|
failureCount: number;
|
|
661
959
|
lastTriggered?: string;
|
|
@@ -669,7 +967,7 @@ interface Webhook {
|
|
|
669
967
|
interface CreateWebhookInput {
|
|
670
968
|
url: string;
|
|
671
969
|
secret: string;
|
|
672
|
-
events:
|
|
970
|
+
events: WebhookEventName[];
|
|
673
971
|
}
|
|
674
972
|
/**
|
|
675
973
|
* Webhook delivery record
|
|
@@ -677,7 +975,7 @@ interface CreateWebhookInput {
|
|
|
677
975
|
interface WebhookDelivery {
|
|
678
976
|
id: string;
|
|
679
977
|
webhookId: string;
|
|
680
|
-
event:
|
|
978
|
+
event: WebhookEventName;
|
|
681
979
|
payload: Record<string, unknown>;
|
|
682
980
|
status: 'PENDING' | 'SUCCESS' | 'FAILED' | 'RETRYING';
|
|
683
981
|
attempts: number;
|
|
@@ -896,10 +1194,30 @@ declare class FieldsResource extends BaseResource {
|
|
|
896
1194
|
|
|
897
1195
|
/**
|
|
898
1196
|
* Configuration options for the Dispatch Tickets client
|
|
1197
|
+
*
|
|
1198
|
+
* @example
|
|
1199
|
+
* ```typescript
|
|
1200
|
+
* const client = new DispatchTickets({
|
|
1201
|
+
* apiKey: 'sk_live_...',
|
|
1202
|
+
* timeout: 30000,
|
|
1203
|
+
* retry: {
|
|
1204
|
+
* maxRetries: 5,
|
|
1205
|
+
* retryableStatuses: [429, 500, 502, 503, 504],
|
|
1206
|
+
* },
|
|
1207
|
+
* hooks: {
|
|
1208
|
+
* onRequest: (ctx) => console.log(`${ctx.method} ${ctx.url}`),
|
|
1209
|
+
* onResponse: (ctx) => console.log(`${ctx.status} in ${ctx.durationMs}ms`),
|
|
1210
|
+
* },
|
|
1211
|
+
* });
|
|
1212
|
+
* ```
|
|
899
1213
|
*/
|
|
900
1214
|
interface DispatchTicketsConfig {
|
|
901
1215
|
/**
|
|
902
1216
|
* Your API key (required)
|
|
1217
|
+
*
|
|
1218
|
+
* Get your API key from the Dispatch Tickets dashboard.
|
|
1219
|
+
* Keys starting with `sk_live_` are production keys.
|
|
1220
|
+
* Keys starting with `sk_test_` are test keys.
|
|
903
1221
|
*/
|
|
904
1222
|
apiKey: string;
|
|
905
1223
|
/**
|
|
@@ -915,18 +1233,90 @@ interface DispatchTicketsConfig {
|
|
|
915
1233
|
/**
|
|
916
1234
|
* Maximum number of retries for failed requests
|
|
917
1235
|
* @default 3
|
|
1236
|
+
* @deprecated Use `retry.maxRetries` instead for fine-grained control
|
|
918
1237
|
*/
|
|
919
1238
|
maxRetries?: number;
|
|
920
1239
|
/**
|
|
921
1240
|
* Enable debug logging
|
|
1241
|
+
*
|
|
1242
|
+
* When enabled, logs all requests, responses, and request IDs to console.
|
|
922
1243
|
* @default false
|
|
923
1244
|
*/
|
|
924
1245
|
debug?: boolean;
|
|
1246
|
+
/**
|
|
1247
|
+
* Custom fetch implementation for testing/mocking
|
|
1248
|
+
*
|
|
1249
|
+
* @example
|
|
1250
|
+
* ```typescript
|
|
1251
|
+
* const mockFetch = vi.fn().mockResolvedValue({
|
|
1252
|
+
* ok: true,
|
|
1253
|
+
* status: 200,
|
|
1254
|
+
* headers: { get: () => 'application/json' },
|
|
1255
|
+
* json: () => Promise.resolve({ id: 'test' }),
|
|
1256
|
+
* });
|
|
1257
|
+
*
|
|
1258
|
+
* const client = new DispatchTickets({
|
|
1259
|
+
* apiKey: 'sk_test_...',
|
|
1260
|
+
* fetch: mockFetch,
|
|
1261
|
+
* });
|
|
1262
|
+
* ```
|
|
1263
|
+
*/
|
|
1264
|
+
fetch?: FetchFunction;
|
|
1265
|
+
/**
|
|
1266
|
+
* Fine-grained retry configuration
|
|
1267
|
+
*
|
|
1268
|
+
* @example
|
|
1269
|
+
* ```typescript
|
|
1270
|
+
* const client = new DispatchTickets({
|
|
1271
|
+
* apiKey: 'sk_live_...',
|
|
1272
|
+
* retry: {
|
|
1273
|
+
* maxRetries: 5,
|
|
1274
|
+
* retryableStatuses: [429, 500, 502, 503, 504],
|
|
1275
|
+
* initialDelayMs: 500,
|
|
1276
|
+
* maxDelayMs: 60000,
|
|
1277
|
+
* backoffMultiplier: 2,
|
|
1278
|
+
* jitter: 0.25,
|
|
1279
|
+
* },
|
|
1280
|
+
* });
|
|
1281
|
+
* ```
|
|
1282
|
+
*/
|
|
1283
|
+
retry?: RetryConfig;
|
|
1284
|
+
/**
|
|
1285
|
+
* Hooks for observability and customization
|
|
1286
|
+
*
|
|
1287
|
+
* @example
|
|
1288
|
+
* ```typescript
|
|
1289
|
+
* const client = new DispatchTickets({
|
|
1290
|
+
* apiKey: 'sk_live_...',
|
|
1291
|
+
* hooks: {
|
|
1292
|
+
* onRequest: (ctx) => {
|
|
1293
|
+
* console.log(`[${new Date().toISOString()}] ${ctx.method} ${ctx.url}`);
|
|
1294
|
+
* },
|
|
1295
|
+
* onResponse: (ctx) => {
|
|
1296
|
+
* console.log(`[${ctx.requestId}] ${ctx.status} in ${ctx.durationMs}ms`);
|
|
1297
|
+
* },
|
|
1298
|
+
* onError: (error, ctx) => {
|
|
1299
|
+
* console.error(`Request failed: ${error.message}`);
|
|
1300
|
+
* // Send to error tracking service
|
|
1301
|
+
* Sentry.captureException(error);
|
|
1302
|
+
* },
|
|
1303
|
+
* onRetry: (ctx, error, delayMs) => {
|
|
1304
|
+
* console.log(`Retrying in ${delayMs}ms (attempt ${ctx.attempt + 1})`);
|
|
1305
|
+
* },
|
|
1306
|
+
* },
|
|
1307
|
+
* });
|
|
1308
|
+
* ```
|
|
1309
|
+
*/
|
|
1310
|
+
hooks?: Hooks;
|
|
925
1311
|
}
|
|
926
1312
|
/**
|
|
927
1313
|
* Dispatch Tickets SDK client
|
|
928
1314
|
*
|
|
929
|
-
*
|
|
1315
|
+
* The main entry point for interacting with the Dispatch Tickets API.
|
|
1316
|
+
* Create a client instance with your API key and use the resource methods
|
|
1317
|
+
* to manage tickets, comments, attachments, and more.
|
|
1318
|
+
*
|
|
1319
|
+
* @example Basic usage
|
|
930
1320
|
* ```typescript
|
|
931
1321
|
* import { DispatchTickets } from '@dispatchtickets/sdk';
|
|
932
1322
|
*
|
|
@@ -948,52 +1338,244 @@ interface DispatchTicketsConfig {
|
|
|
948
1338
|
* console.log(ticket.title);
|
|
949
1339
|
* }
|
|
950
1340
|
* ```
|
|
1341
|
+
*
|
|
1342
|
+
* @example With request cancellation
|
|
1343
|
+
* ```typescript
|
|
1344
|
+
* const controller = new AbortController();
|
|
1345
|
+
*
|
|
1346
|
+
* // Cancel after 5 seconds
|
|
1347
|
+
* setTimeout(() => controller.abort(), 5000);
|
|
1348
|
+
*
|
|
1349
|
+
* try {
|
|
1350
|
+
* const tickets = await client.tickets.listPage('ws_abc123', {}, {
|
|
1351
|
+
* signal: controller.signal,
|
|
1352
|
+
* });
|
|
1353
|
+
* } catch (error) {
|
|
1354
|
+
* if (error.message === 'Request aborted by user') {
|
|
1355
|
+
* console.log('Request was cancelled');
|
|
1356
|
+
* }
|
|
1357
|
+
* }
|
|
1358
|
+
* ```
|
|
1359
|
+
*
|
|
1360
|
+
* @example With hooks for logging
|
|
1361
|
+
* ```typescript
|
|
1362
|
+
* const client = new DispatchTickets({
|
|
1363
|
+
* apiKey: 'sk_live_...',
|
|
1364
|
+
* hooks: {
|
|
1365
|
+
* onRequest: (ctx) => console.log(`→ ${ctx.method} ${ctx.url}`),
|
|
1366
|
+
* onResponse: (ctx) => console.log(`← ${ctx.status} (${ctx.durationMs}ms)`),
|
|
1367
|
+
* },
|
|
1368
|
+
* });
|
|
1369
|
+
* ```
|
|
951
1370
|
*/
|
|
952
1371
|
declare class DispatchTickets {
|
|
953
1372
|
private readonly http;
|
|
1373
|
+
/**
|
|
1374
|
+
* Accounts resource for managing the current account and API keys
|
|
1375
|
+
*
|
|
1376
|
+
* @example
|
|
1377
|
+
* ```typescript
|
|
1378
|
+
* // Get current account
|
|
1379
|
+
* const account = await client.accounts.me();
|
|
1380
|
+
*
|
|
1381
|
+
* // Get usage statistics
|
|
1382
|
+
* const usage = await client.accounts.getUsage();
|
|
1383
|
+
*
|
|
1384
|
+
* // Create a new API key
|
|
1385
|
+
* const newKey = await client.accounts.createApiKey({
|
|
1386
|
+
* name: 'Production',
|
|
1387
|
+
* allBrands: true,
|
|
1388
|
+
* });
|
|
1389
|
+
* ```
|
|
1390
|
+
*/
|
|
1391
|
+
readonly accounts: AccountsResource;
|
|
954
1392
|
/**
|
|
955
1393
|
* Brands (workspaces) resource
|
|
1394
|
+
*
|
|
1395
|
+
* Brands are isolated containers for tickets. Each brand can have its own
|
|
1396
|
+
* email address, categories, tags, and settings.
|
|
1397
|
+
*
|
|
1398
|
+
* @example
|
|
1399
|
+
* ```typescript
|
|
1400
|
+
* // List all brands
|
|
1401
|
+
* const brands = await client.brands.list();
|
|
1402
|
+
*
|
|
1403
|
+
* // Create a new brand
|
|
1404
|
+
* const brand = await client.brands.create({
|
|
1405
|
+
* name: 'Acme Support',
|
|
1406
|
+
* slug: 'acme',
|
|
1407
|
+
* });
|
|
1408
|
+
*
|
|
1409
|
+
* // Get inbound email address
|
|
1410
|
+
* const email = client.brands.getInboundEmail('br_abc123');
|
|
1411
|
+
* // Returns: br_abc123@inbound.dispatchtickets.com
|
|
1412
|
+
* ```
|
|
956
1413
|
*/
|
|
957
1414
|
readonly brands: BrandsResource;
|
|
958
1415
|
/**
|
|
959
1416
|
* Tickets resource
|
|
1417
|
+
*
|
|
1418
|
+
* @example
|
|
1419
|
+
* ```typescript
|
|
1420
|
+
* // Create a ticket
|
|
1421
|
+
* const ticket = await client.tickets.create('ws_abc123', {
|
|
1422
|
+
* title: 'Issue with billing',
|
|
1423
|
+
* body: 'I was charged twice...',
|
|
1424
|
+
* priority: 'high',
|
|
1425
|
+
* });
|
|
1426
|
+
*
|
|
1427
|
+
* // Iterate through all tickets
|
|
1428
|
+
* for await (const ticket of client.tickets.list('ws_abc123', { status: 'open' })) {
|
|
1429
|
+
* console.log(ticket.title);
|
|
1430
|
+
* }
|
|
1431
|
+
* ```
|
|
960
1432
|
*/
|
|
961
1433
|
readonly tickets: TicketsResource;
|
|
962
1434
|
/**
|
|
963
1435
|
* Comments resource
|
|
1436
|
+
*
|
|
1437
|
+
* @example
|
|
1438
|
+
* ```typescript
|
|
1439
|
+
* // Add a comment
|
|
1440
|
+
* const comment = await client.comments.create('ws_abc123', 'tkt_xyz', {
|
|
1441
|
+
* body: 'Thanks for your patience!',
|
|
1442
|
+
* authorType: 'AGENT',
|
|
1443
|
+
* });
|
|
1444
|
+
*
|
|
1445
|
+
* // List comments
|
|
1446
|
+
* const comments = await client.comments.list('ws_abc123', 'tkt_xyz');
|
|
1447
|
+
* ```
|
|
964
1448
|
*/
|
|
965
1449
|
readonly comments: CommentsResource;
|
|
966
1450
|
/**
|
|
967
1451
|
* Attachments resource
|
|
1452
|
+
*
|
|
1453
|
+
* @example
|
|
1454
|
+
* ```typescript
|
|
1455
|
+
* // Simple upload
|
|
1456
|
+
* const attachment = await client.attachments.upload(
|
|
1457
|
+
* 'ws_abc123',
|
|
1458
|
+
* 'tkt_xyz',
|
|
1459
|
+
* fileBuffer,
|
|
1460
|
+
* 'document.pdf',
|
|
1461
|
+
* 'application/pdf'
|
|
1462
|
+
* );
|
|
1463
|
+
*
|
|
1464
|
+
* // Get download URL
|
|
1465
|
+
* const { downloadUrl } = await client.attachments.get('ws_abc123', 'tkt_xyz', 'att_abc');
|
|
1466
|
+
* ```
|
|
968
1467
|
*/
|
|
969
1468
|
readonly attachments: AttachmentsResource;
|
|
970
1469
|
/**
|
|
971
1470
|
* Webhooks resource
|
|
1471
|
+
*
|
|
1472
|
+
* @example
|
|
1473
|
+
* ```typescript
|
|
1474
|
+
* // Create a webhook
|
|
1475
|
+
* const webhook = await client.webhooks.create('ws_abc123', {
|
|
1476
|
+
* url: 'https://example.com/webhook',
|
|
1477
|
+
* secret: 'your-secret',
|
|
1478
|
+
* events: ['ticket.created', 'ticket.updated'],
|
|
1479
|
+
* });
|
|
1480
|
+
* ```
|
|
972
1481
|
*/
|
|
973
1482
|
readonly webhooks: WebhooksResource;
|
|
974
1483
|
/**
|
|
975
1484
|
* Categories resource
|
|
1485
|
+
*
|
|
1486
|
+
* @example
|
|
1487
|
+
* ```typescript
|
|
1488
|
+
* // Create a category
|
|
1489
|
+
* await client.categories.create('ws_abc123', { name: 'Billing', color: '#ef4444' });
|
|
1490
|
+
*
|
|
1491
|
+
* // Get category stats
|
|
1492
|
+
* const stats = await client.categories.getStats('ws_abc123');
|
|
1493
|
+
* ```
|
|
976
1494
|
*/
|
|
977
1495
|
readonly categories: CategoriesResource;
|
|
978
1496
|
/**
|
|
979
1497
|
* Tags resource
|
|
1498
|
+
*
|
|
1499
|
+
* @example
|
|
1500
|
+
* ```typescript
|
|
1501
|
+
* // Create a tag
|
|
1502
|
+
* await client.tags.create('ws_abc123', { name: 'urgent', color: '#f59e0b' });
|
|
1503
|
+
*
|
|
1504
|
+
* // Merge tags
|
|
1505
|
+
* await client.tags.merge('ws_abc123', 'tag_target', ['tag_source1', 'tag_source2']);
|
|
1506
|
+
* ```
|
|
980
1507
|
*/
|
|
981
1508
|
readonly tags: TagsResource;
|
|
982
1509
|
/**
|
|
983
1510
|
* Customers resource
|
|
1511
|
+
*
|
|
1512
|
+
* @example
|
|
1513
|
+
* ```typescript
|
|
1514
|
+
* // Create a customer
|
|
1515
|
+
* const customer = await client.customers.create('ws_abc123', {
|
|
1516
|
+
* email: 'user@example.com',
|
|
1517
|
+
* name: 'Jane Doe',
|
|
1518
|
+
* });
|
|
1519
|
+
*
|
|
1520
|
+
* // Search customers
|
|
1521
|
+
* const results = await client.customers.search('ws_abc123', 'jane');
|
|
1522
|
+
* ```
|
|
984
1523
|
*/
|
|
985
1524
|
readonly customers: CustomersResource;
|
|
986
1525
|
/**
|
|
987
1526
|
* Custom fields resource
|
|
1527
|
+
*
|
|
1528
|
+
* @example
|
|
1529
|
+
* ```typescript
|
|
1530
|
+
* // Get all field definitions
|
|
1531
|
+
* const fields = await client.fields.getAll('ws_abc123');
|
|
1532
|
+
*
|
|
1533
|
+
* // Create a field
|
|
1534
|
+
* await client.fields.create('ws_abc123', 'ticket', {
|
|
1535
|
+
* key: 'order_id',
|
|
1536
|
+
* label: 'Order ID',
|
|
1537
|
+
* type: 'text',
|
|
1538
|
+
* required: true,
|
|
1539
|
+
* });
|
|
1540
|
+
* ```
|
|
988
1541
|
*/
|
|
989
1542
|
readonly fields: FieldsResource;
|
|
990
1543
|
/**
|
|
991
1544
|
* Static webhook utilities
|
|
1545
|
+
*
|
|
1546
|
+
* @example
|
|
1547
|
+
* ```typescript
|
|
1548
|
+
* // Verify webhook signature
|
|
1549
|
+
* const isValid = DispatchTickets.webhooks.verifySignature(
|
|
1550
|
+
* rawBody,
|
|
1551
|
+
* req.headers['x-dispatch-signature'],
|
|
1552
|
+
* 'your-secret'
|
|
1553
|
+
* );
|
|
1554
|
+
*
|
|
1555
|
+
* // Generate signature for testing
|
|
1556
|
+
* const signature = DispatchTickets.webhooks.generateSignature(
|
|
1557
|
+
* JSON.stringify(payload),
|
|
1558
|
+
* 'your-secret'
|
|
1559
|
+
* );
|
|
1560
|
+
* ```
|
|
992
1561
|
*/
|
|
993
1562
|
static readonly webhooks: {
|
|
994
1563
|
verifySignature(payload: string, signature: string, secret: string): boolean;
|
|
995
1564
|
generateSignature(payload: string, secret: string): string;
|
|
996
1565
|
};
|
|
1566
|
+
/**
|
|
1567
|
+
* Create a new Dispatch Tickets client
|
|
1568
|
+
*
|
|
1569
|
+
* @param config - Client configuration options
|
|
1570
|
+
* @throws Error if API key is not provided
|
|
1571
|
+
*
|
|
1572
|
+
* @example
|
|
1573
|
+
* ```typescript
|
|
1574
|
+
* const client = new DispatchTickets({
|
|
1575
|
+
* apiKey: 'sk_live_...',
|
|
1576
|
+
* });
|
|
1577
|
+
* ```
|
|
1578
|
+
*/
|
|
997
1579
|
constructor(config: DispatchTicketsConfig);
|
|
998
1580
|
}
|
|
999
1581
|
|
|
@@ -1004,20 +1586,32 @@ declare class DispatchTicketsError extends Error {
|
|
|
1004
1586
|
readonly code: string;
|
|
1005
1587
|
readonly statusCode?: number;
|
|
1006
1588
|
readonly details?: Record<string, unknown>;
|
|
1007
|
-
|
|
1589
|
+
/** Request ID for debugging with support */
|
|
1590
|
+
readonly requestId?: string;
|
|
1591
|
+
constructor(message: string, code: string, statusCode?: number, details?: Record<string, unknown>, requestId?: string);
|
|
1008
1592
|
}
|
|
1009
1593
|
/**
|
|
1010
1594
|
* Thrown when API key is missing or invalid
|
|
1011
1595
|
*/
|
|
1012
1596
|
declare class AuthenticationError extends DispatchTicketsError {
|
|
1013
|
-
constructor(message?: string);
|
|
1597
|
+
constructor(message?: string, requestId?: string);
|
|
1014
1598
|
}
|
|
1015
1599
|
/**
|
|
1016
1600
|
* Thrown when rate limit is exceeded
|
|
1017
1601
|
*/
|
|
1018
1602
|
declare class RateLimitError extends DispatchTicketsError {
|
|
1019
1603
|
readonly retryAfter?: number;
|
|
1020
|
-
|
|
1604
|
+
/** Rate limit ceiling */
|
|
1605
|
+
readonly limit?: number;
|
|
1606
|
+
/** Remaining requests in current window */
|
|
1607
|
+
readonly remaining?: number;
|
|
1608
|
+
/** Unix timestamp when rate limit resets */
|
|
1609
|
+
readonly reset?: number;
|
|
1610
|
+
constructor(message?: string, retryAfter?: number, requestId?: string, rateLimitInfo?: {
|
|
1611
|
+
limit?: number;
|
|
1612
|
+
remaining?: number;
|
|
1613
|
+
reset?: number;
|
|
1614
|
+
});
|
|
1021
1615
|
}
|
|
1022
1616
|
/**
|
|
1023
1617
|
* Thrown when request validation fails
|
|
@@ -1030,7 +1624,7 @@ declare class ValidationError extends DispatchTicketsError {
|
|
|
1030
1624
|
constructor(message?: string, errors?: Array<{
|
|
1031
1625
|
field: string;
|
|
1032
1626
|
message: string;
|
|
1033
|
-
}
|
|
1627
|
+
}>, requestId?: string);
|
|
1034
1628
|
}
|
|
1035
1629
|
/**
|
|
1036
1630
|
* Thrown when a resource is not found
|
|
@@ -1038,19 +1632,19 @@ declare class ValidationError extends DispatchTicketsError {
|
|
|
1038
1632
|
declare class NotFoundError extends DispatchTicketsError {
|
|
1039
1633
|
readonly resourceType?: string;
|
|
1040
1634
|
readonly resourceId?: string;
|
|
1041
|
-
constructor(message?: string, resourceType?: string, resourceId?: string);
|
|
1635
|
+
constructor(message?: string, resourceType?: string, resourceId?: string, requestId?: string);
|
|
1042
1636
|
}
|
|
1043
1637
|
/**
|
|
1044
1638
|
* Thrown when there's a conflict (e.g., duplicate resource)
|
|
1045
1639
|
*/
|
|
1046
1640
|
declare class ConflictError extends DispatchTicketsError {
|
|
1047
|
-
constructor(message?: string);
|
|
1641
|
+
constructor(message?: string, requestId?: string);
|
|
1048
1642
|
}
|
|
1049
1643
|
/**
|
|
1050
1644
|
* Thrown when the server returns an unexpected error
|
|
1051
1645
|
*/
|
|
1052
1646
|
declare class ServerError extends DispatchTicketsError {
|
|
1053
|
-
constructor(message?: string, statusCode?: number);
|
|
1647
|
+
constructor(message?: string, statusCode?: number, requestId?: string);
|
|
1054
1648
|
}
|
|
1055
1649
|
/**
|
|
1056
1650
|
* Thrown when request times out
|
|
@@ -1064,6 +1658,172 @@ declare class TimeoutError extends DispatchTicketsError {
|
|
|
1064
1658
|
declare class NetworkError extends DispatchTicketsError {
|
|
1065
1659
|
constructor(message?: string);
|
|
1066
1660
|
}
|
|
1661
|
+
/**
|
|
1662
|
+
* Check if an error is a DispatchTicketsError
|
|
1663
|
+
*/
|
|
1664
|
+
declare function isDispatchTicketsError(error: unknown): error is DispatchTicketsError;
|
|
1665
|
+
/**
|
|
1666
|
+
* Check if an error is an AuthenticationError
|
|
1667
|
+
*/
|
|
1668
|
+
declare function isAuthenticationError(error: unknown): error is AuthenticationError;
|
|
1669
|
+
/**
|
|
1670
|
+
* Check if an error is a RateLimitError
|
|
1671
|
+
*/
|
|
1672
|
+
declare function isRateLimitError(error: unknown): error is RateLimitError;
|
|
1673
|
+
/**
|
|
1674
|
+
* Check if an error is a ValidationError
|
|
1675
|
+
*/
|
|
1676
|
+
declare function isValidationError(error: unknown): error is ValidationError;
|
|
1677
|
+
/**
|
|
1678
|
+
* Check if an error is a NotFoundError
|
|
1679
|
+
*/
|
|
1680
|
+
declare function isNotFoundError(error: unknown): error is NotFoundError;
|
|
1681
|
+
/**
|
|
1682
|
+
* Check if an error is a ConflictError
|
|
1683
|
+
*/
|
|
1684
|
+
declare function isConflictError(error: unknown): error is ConflictError;
|
|
1685
|
+
/**
|
|
1686
|
+
* Check if an error is a ServerError
|
|
1687
|
+
*/
|
|
1688
|
+
declare function isServerError(error: unknown): error is ServerError;
|
|
1689
|
+
/**
|
|
1690
|
+
* Check if an error is a TimeoutError
|
|
1691
|
+
*/
|
|
1692
|
+
declare function isTimeoutError(error: unknown): error is TimeoutError;
|
|
1693
|
+
/**
|
|
1694
|
+
* Check if an error is a NetworkError
|
|
1695
|
+
*/
|
|
1696
|
+
declare function isNetworkError(error: unknown): error is NetworkError;
|
|
1697
|
+
|
|
1698
|
+
/**
|
|
1699
|
+
* All supported webhook event types
|
|
1700
|
+
*/
|
|
1701
|
+
type WebhookEventType = 'ticket.created' | 'ticket.updated' | 'ticket.comment.created';
|
|
1702
|
+
/**
|
|
1703
|
+
* Base webhook event envelope
|
|
1704
|
+
*/
|
|
1705
|
+
interface WebhookEventEnvelope<T extends WebhookEventType, D> {
|
|
1706
|
+
/** Unique event ID */
|
|
1707
|
+
id: string;
|
|
1708
|
+
/** Event type */
|
|
1709
|
+
event: T;
|
|
1710
|
+
/** Brand ID that triggered the event */
|
|
1711
|
+
brand_id: string;
|
|
1712
|
+
/** Event data */
|
|
1713
|
+
data: D;
|
|
1714
|
+
/** ISO timestamp when event was created */
|
|
1715
|
+
timestamp: string;
|
|
1716
|
+
}
|
|
1717
|
+
/**
|
|
1718
|
+
* Customer info included in events
|
|
1719
|
+
*/
|
|
1720
|
+
interface EventCustomerInfo {
|
|
1721
|
+
customerId: string | null;
|
|
1722
|
+
customerEmail: string | null;
|
|
1723
|
+
customerName: string | null;
|
|
1724
|
+
}
|
|
1725
|
+
/**
|
|
1726
|
+
* Payload for ticket.created event
|
|
1727
|
+
*/
|
|
1728
|
+
interface TicketCreatedData extends EventCustomerInfo {
|
|
1729
|
+
id: string;
|
|
1730
|
+
ticketNumber: number;
|
|
1731
|
+
title: string;
|
|
1732
|
+
status: TicketStatus;
|
|
1733
|
+
priority: TicketPriority;
|
|
1734
|
+
source: TicketSource;
|
|
1735
|
+
createdAt: string;
|
|
1736
|
+
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Payload for ticket.updated event
|
|
1739
|
+
*/
|
|
1740
|
+
interface TicketUpdatedData extends EventCustomerInfo {
|
|
1741
|
+
id: string;
|
|
1742
|
+
ticketNumber: number;
|
|
1743
|
+
title: string;
|
|
1744
|
+
status: TicketStatus;
|
|
1745
|
+
priority: TicketPriority;
|
|
1746
|
+
assigneeId: string | null;
|
|
1747
|
+
updatedAt: string;
|
|
1748
|
+
/** List of field names that were changed */
|
|
1749
|
+
changes: string[];
|
|
1750
|
+
}
|
|
1751
|
+
/**
|
|
1752
|
+
* Comment data in ticket.comment.created event
|
|
1753
|
+
*/
|
|
1754
|
+
interface EventCommentData {
|
|
1755
|
+
id: string;
|
|
1756
|
+
body: string;
|
|
1757
|
+
authorId: string | null;
|
|
1758
|
+
authorType: AuthorType;
|
|
1759
|
+
createdAt: string;
|
|
1760
|
+
}
|
|
1761
|
+
/**
|
|
1762
|
+
* Payload for ticket.comment.created event
|
|
1763
|
+
*/
|
|
1764
|
+
interface CommentCreatedData extends EventCustomerInfo {
|
|
1765
|
+
ticketId: string;
|
|
1766
|
+
/** Formatted ticket number (e.g., "ACME-123") */
|
|
1767
|
+
ticketNumber: string;
|
|
1768
|
+
comment: EventCommentData;
|
|
1769
|
+
}
|
|
1770
|
+
/**
|
|
1771
|
+
* Ticket created webhook event
|
|
1772
|
+
*/
|
|
1773
|
+
type TicketCreatedEvent = WebhookEventEnvelope<'ticket.created', TicketCreatedData>;
|
|
1774
|
+
/**
|
|
1775
|
+
* Ticket updated webhook event
|
|
1776
|
+
*/
|
|
1777
|
+
type TicketUpdatedEvent = WebhookEventEnvelope<'ticket.updated', TicketUpdatedData>;
|
|
1778
|
+
/**
|
|
1779
|
+
* Comment created webhook event
|
|
1780
|
+
*/
|
|
1781
|
+
type CommentCreatedEvent = WebhookEventEnvelope<'ticket.comment.created', CommentCreatedData>;
|
|
1782
|
+
/**
|
|
1783
|
+
* Union of all webhook events
|
|
1784
|
+
*/
|
|
1785
|
+
type WebhookEvent = TicketCreatedEvent | TicketUpdatedEvent | CommentCreatedEvent;
|
|
1786
|
+
/**
|
|
1787
|
+
* Map of event types to their data types
|
|
1788
|
+
*/
|
|
1789
|
+
interface WebhookEventMap {
|
|
1790
|
+
'ticket.created': TicketCreatedEvent;
|
|
1791
|
+
'ticket.updated': TicketUpdatedEvent;
|
|
1792
|
+
'ticket.comment.created': CommentCreatedEvent;
|
|
1793
|
+
}
|
|
1794
|
+
/**
|
|
1795
|
+
* Type guard to check if event is a ticket.created event
|
|
1796
|
+
*/
|
|
1797
|
+
declare function isTicketCreatedEvent(event: WebhookEvent): event is TicketCreatedEvent;
|
|
1798
|
+
/**
|
|
1799
|
+
* Type guard to check if event is a ticket.updated event
|
|
1800
|
+
*/
|
|
1801
|
+
declare function isTicketUpdatedEvent(event: WebhookEvent): event is TicketUpdatedEvent;
|
|
1802
|
+
/**
|
|
1803
|
+
* Type guard to check if event is a ticket.comment.created event
|
|
1804
|
+
*/
|
|
1805
|
+
declare function isCommentCreatedEvent(event: WebhookEvent): event is CommentCreatedEvent;
|
|
1806
|
+
/**
|
|
1807
|
+
* Parse and validate a webhook payload
|
|
1808
|
+
*
|
|
1809
|
+
* @param payload - Raw JSON payload string or parsed object
|
|
1810
|
+
* @returns Typed webhook event
|
|
1811
|
+
* @throws Error if payload is invalid
|
|
1812
|
+
*
|
|
1813
|
+
* @example
|
|
1814
|
+
* ```typescript
|
|
1815
|
+
* import { parseWebhookEvent, isTicketCreatedEvent } from '@dispatchtickets/sdk';
|
|
1816
|
+
*
|
|
1817
|
+
* app.post('/webhooks', (req, res) => {
|
|
1818
|
+
* const event = parseWebhookEvent(req.body);
|
|
1819
|
+
*
|
|
1820
|
+
* if (isTicketCreatedEvent(event)) {
|
|
1821
|
+
* console.log('New ticket:', event.data.title);
|
|
1822
|
+
* }
|
|
1823
|
+
* });
|
|
1824
|
+
* ```
|
|
1825
|
+
*/
|
|
1826
|
+
declare function parseWebhookEvent(payload: string | object): WebhookEvent;
|
|
1067
1827
|
|
|
1068
1828
|
/**
|
|
1069
1829
|
* Webhook signature verification utilities
|
|
@@ -1113,4 +1873,4 @@ declare const webhookUtils: {
|
|
|
1113
1873
|
*/
|
|
1114
1874
|
declare function collectAll<T>(iterable: AsyncIterable<T>): Promise<T[]>;
|
|
1115
1875
|
|
|
1116
|
-
export { type Attachment, type AttachmentStatus, type AttachmentWithUrl, AuthenticationError, type AuthorType, type Brand, type BulkAction, type BulkActionResult, type Category, type CategoryStats, type Comment, type Company, ConflictError, type CreateBrandInput, type CreateCategoryInput, type CreateCommentInput, type CreateCommentOptions, type CreateCustomerInput, type CreateFieldInput, type CreateTagInput, type CreateTicketInput, type CreateTicketOptions, type CreateWebhookInput, type Customer, type DeleteBrandPreview, DispatchTickets, type DispatchTicketsConfig, DispatchTicketsError, type EntityType, type FieldDefinition, type FieldDefinitions, type FieldType, type InitiateUploadInput, type InitiateUploadResponse, type Link, type ListCustomersFilters, type ListTicketsFilters, type MergeTagsInput, type MergeTicketsInput, NetworkError, NotFoundError, type PaginatedResponse, RateLimitError, ServerError, type SortOrder, type Tag, type Ticket, type TicketPriority, type TicketSource, type TicketStatus, TimeoutError, type UpdateBrandInput, type UpdateCategoryInput, type UpdateCommentInput, type UpdateCustomerInput, type UpdateFieldInput, type UpdateTagInput, type UpdateTicketInput, ValidationError, type Webhook, type WebhookDelivery, type WebhookEvent, collectAll, webhookUtils };
|
|
1876
|
+
export { type Account, type AccountUsage, type ApiKey, type ApiKeyWithSecret, type ApiRequestOptions, type Attachment, type AttachmentStatus, type AttachmentWithUrl, AuthenticationError, type AuthorType, type Brand, type BulkAction, type BulkActionResult, type Category, type CategoryStats, type Comment, type CommentCreatedData, type CommentCreatedEvent, type Company, ConflictError, type CreateApiKeyInput, type CreateBrandInput, type CreateCategoryInput, type CreateCommentInput, type CreateCommentOptions, type CreateCustomerInput, type CreateFieldInput, type CreateTagInput, type CreateTicketInput, type CreateTicketOptions, type CreateWebhookInput, type Customer, type DeleteBrandPreview, DispatchTickets, type DispatchTicketsConfig, DispatchTicketsError, type EntityType, type EventCommentData, type EventCustomerInfo, type FieldDefinition, type FieldDefinitions, type FieldType, type Hooks, type InitiateUploadInput, type InitiateUploadResponse, type Link, type ListCustomersFilters, type ListTicketsFilters, type MergeTagsInput, type MergeTicketsInput, NetworkError, NotFoundError, type PaginatedResponse, RateLimitError, type RateLimitInfo, type RequestContext, type ResponseContext, type RetryConfig, ServerError, type SortOrder, type Tag, type Ticket, type TicketCreatedData, type TicketCreatedEvent, type TicketPriority, type TicketSource, type TicketStatus, type TicketUpdatedData, type TicketUpdatedEvent, TimeoutError, type UpdateApiKeyScopeInput, type UpdateBrandInput, type UpdateCategoryInput, type UpdateCommentInput, type UpdateCustomerInput, type UpdateFieldInput, type UpdateTagInput, type UpdateTicketInput, ValidationError, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookEventEnvelope, type WebhookEventMap, type WebhookEventName, type WebhookEventType, collectAll, isAuthenticationError, isCommentCreatedEvent, isConflictError, isDispatchTicketsError, isNetworkError, isNotFoundError, isRateLimitError, isServerError, isTicketCreatedEvent, isTicketUpdatedEvent, isTimeoutError, isValidationError, parseWebhookEvent, webhookUtils };
|