@veroai/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,1946 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ // src/utils/errors.ts
6
+ var VeroAIError = class extends Error {
7
+ code;
8
+ details;
9
+ statusCode;
10
+ constructor(message, code = "UNKNOWN_ERROR", statusCode, details) {
11
+ super(message);
12
+ this.name = "VeroAIError";
13
+ this.code = code;
14
+ this.statusCode = statusCode;
15
+ this.details = details;
16
+ if (Error.captureStackTrace) {
17
+ Error.captureStackTrace(this, this.constructor);
18
+ }
19
+ }
20
+ toJSON() {
21
+ return {
22
+ code: this.code,
23
+ message: this.message,
24
+ details: this.details
25
+ };
26
+ }
27
+ };
28
+ var APIError = class extends VeroAIError {
29
+ response;
30
+ constructor(message, code, statusCode, details, response) {
31
+ super(message, code, statusCode, details);
32
+ this.name = "APIError";
33
+ this.response = response;
34
+ }
35
+ };
36
+ var AuthenticationError = class extends APIError {
37
+ constructor(message = "Invalid API key or token", details) {
38
+ super(message, "AUTHENTICATION_ERROR", 401, details);
39
+ this.name = "AuthenticationError";
40
+ }
41
+ };
42
+ var AuthorizationError = class extends APIError {
43
+ constructor(message = "Insufficient permissions", details) {
44
+ super(message, "AUTHORIZATION_ERROR", 403, details);
45
+ this.name = "AuthorizationError";
46
+ }
47
+ };
48
+ var NotFoundError = class extends APIError {
49
+ constructor(message = "Resource not found", details) {
50
+ super(message, "NOT_FOUND", 404, details);
51
+ this.name = "NotFoundError";
52
+ }
53
+ };
54
+ var ValidationError = class extends APIError {
55
+ constructor(message = "Invalid request", details) {
56
+ super(message, "VALIDATION_ERROR", 400, details);
57
+ this.name = "ValidationError";
58
+ }
59
+ };
60
+ var RateLimitError = class extends APIError {
61
+ retryAfter;
62
+ constructor(message = "Rate limit exceeded", retryAfter, details) {
63
+ super(message, "RATE_LIMIT_EXCEEDED", 429, details);
64
+ this.name = "RateLimitError";
65
+ this.retryAfter = retryAfter;
66
+ }
67
+ };
68
+ var ServerError = class extends APIError {
69
+ constructor(message = "Internal server error", statusCode = 500, details) {
70
+ super(message, "SERVER_ERROR", statusCode, details);
71
+ this.name = "ServerError";
72
+ }
73
+ };
74
+ var TimeoutError = class extends VeroAIError {
75
+ constructor(message = "Request timed out") {
76
+ super(message, "TIMEOUT_ERROR");
77
+ this.name = "TimeoutError";
78
+ }
79
+ };
80
+ var NetworkError = class extends VeroAIError {
81
+ constructor(message = "Network error", cause) {
82
+ super(message, "NETWORK_ERROR");
83
+ this.name = "NetworkError";
84
+ this.cause = cause;
85
+ }
86
+ };
87
+
88
+ // src/utils/http.ts
89
+ var HttpClient = class {
90
+ apiKey;
91
+ baseUrl;
92
+ timeout;
93
+ maxRetries;
94
+ fetchFn;
95
+ constructor(config) {
96
+ this.apiKey = config.apiKey;
97
+ this.baseUrl = config.baseUrl?.replace(/\/$/, "") || "https://api.veroai.dev";
98
+ this.timeout = config.timeout || 3e4;
99
+ this.maxRetries = config.maxRetries ?? 3;
100
+ this.fetchFn = config.fetch || globalThis.fetch;
101
+ if (!this.apiKey) {
102
+ throw new Error("API key is required");
103
+ }
104
+ if (!this.fetchFn) {
105
+ throw new Error(
106
+ "fetch is not available. Please provide a fetch implementation or use Node.js >= 18."
107
+ );
108
+ }
109
+ }
110
+ async request(options) {
111
+ const url = this.buildUrl(options.path, options.query);
112
+ const headers = this.buildHeaders(options.headers);
113
+ const timeout = options.timeout || this.timeout;
114
+ let lastError = null;
115
+ let attempt = 0;
116
+ while (attempt <= this.maxRetries) {
117
+ try {
118
+ const response = await this.executeRequest(url, {
119
+ method: options.method,
120
+ headers,
121
+ body: options.body ? JSON.stringify(options.body) : void 0,
122
+ timeout
123
+ });
124
+ if (!response.ok) {
125
+ const error = await this.handleErrorResponse(response);
126
+ if (response.status >= 500 || response.status === 429) {
127
+ const retryAfter = this.getRetryAfter(response, attempt);
128
+ if (attempt < this.maxRetries && retryAfter > 0) {
129
+ await this.sleep(retryAfter);
130
+ attempt++;
131
+ continue;
132
+ }
133
+ }
134
+ throw error;
135
+ }
136
+ if (response.status === 204) {
137
+ return void 0;
138
+ }
139
+ return await response.json();
140
+ } catch (error) {
141
+ if (error instanceof APIError) {
142
+ throw error;
143
+ }
144
+ lastError = error;
145
+ if (attempt < this.maxRetries) {
146
+ await this.sleep(this.calculateBackoff(attempt));
147
+ attempt++;
148
+ continue;
149
+ }
150
+ if (error instanceof TypeError && error.message.includes("fetch")) {
151
+ throw new NetworkError("Failed to connect to API", error);
152
+ }
153
+ throw error;
154
+ }
155
+ }
156
+ throw lastError || new NetworkError("Request failed after retries");
157
+ }
158
+ async executeRequest(url, options) {
159
+ const controller = new AbortController();
160
+ const timeoutId = setTimeout(() => controller.abort(), options.timeout);
161
+ try {
162
+ return await this.fetchFn(url, {
163
+ method: options.method,
164
+ headers: options.headers,
165
+ body: options.body,
166
+ signal: controller.signal
167
+ });
168
+ } catch (error) {
169
+ if (error instanceof Error && error.name === "AbortError") {
170
+ throw new TimeoutError(`Request timed out after ${options.timeout}ms`);
171
+ }
172
+ throw error;
173
+ } finally {
174
+ clearTimeout(timeoutId);
175
+ }
176
+ }
177
+ buildUrl(path, query) {
178
+ const url = new URL(path.startsWith("/") ? path : `/${path}`, this.baseUrl);
179
+ if (query) {
180
+ for (const [key, value] of Object.entries(query)) {
181
+ if (value !== void 0) {
182
+ url.searchParams.set(key, String(value));
183
+ }
184
+ }
185
+ }
186
+ return url.toString();
187
+ }
188
+ buildHeaders(custom) {
189
+ const headers = new Headers({
190
+ "Authorization": `Bearer ${this.apiKey}`,
191
+ "Content-Type": "application/json",
192
+ "Accept": "application/json",
193
+ "User-Agent": "@veroai/sdk/0.1.0"
194
+ });
195
+ if (custom) {
196
+ for (const [key, value] of Object.entries(custom)) {
197
+ headers.set(key, value);
198
+ }
199
+ }
200
+ return headers;
201
+ }
202
+ async handleErrorResponse(response) {
203
+ let errorData = {};
204
+ try {
205
+ const json = await response.json();
206
+ if (json && typeof json === "object") {
207
+ errorData = json;
208
+ }
209
+ } catch {
210
+ }
211
+ const code = errorData.error?.code || "API_ERROR";
212
+ const message = errorData.error?.message || response.statusText || "Unknown error";
213
+ const details = errorData.error?.details;
214
+ switch (response.status) {
215
+ case 400:
216
+ return new ValidationError(message, details);
217
+ case 401:
218
+ return new AuthenticationError(message, details);
219
+ case 403:
220
+ return new AuthorizationError(message, details);
221
+ case 404:
222
+ return new NotFoundError(message, details);
223
+ case 429: {
224
+ const retryAfter = parseInt(response.headers.get("Retry-After") || "60", 10);
225
+ return new RateLimitError(message, retryAfter, details);
226
+ }
227
+ default:
228
+ if (response.status >= 500) {
229
+ return new ServerError(message, response.status, details);
230
+ }
231
+ return new APIError(message, code, response.status, details, response);
232
+ }
233
+ }
234
+ getRetryAfter(response, attempt) {
235
+ const retryAfterHeader = response.headers.get("Retry-After");
236
+ if (retryAfterHeader) {
237
+ const retryAfter = parseInt(retryAfterHeader, 10);
238
+ if (!isNaN(retryAfter)) {
239
+ return retryAfter * 1e3;
240
+ }
241
+ }
242
+ return this.calculateBackoff(attempt);
243
+ }
244
+ calculateBackoff(attempt) {
245
+ const baseDelay = Math.min(1e3 * Math.pow(2, attempt), 3e4);
246
+ const jitter = Math.random() * 1e3;
247
+ return baseDelay + jitter;
248
+ }
249
+ sleep(ms) {
250
+ return new Promise((resolve) => setTimeout(resolve, ms));
251
+ }
252
+ // Convenience methods
253
+ async get(path, query) {
254
+ return this.request({ method: "GET", path, query });
255
+ }
256
+ async post(path, body) {
257
+ return this.request({ method: "POST", path, body });
258
+ }
259
+ async put(path, body) {
260
+ return this.request({ method: "PUT", path, body });
261
+ }
262
+ async patch(path, body) {
263
+ return this.request({ method: "PATCH", path, body });
264
+ }
265
+ async delete(path) {
266
+ return this.request({ method: "DELETE", path });
267
+ }
268
+ };
269
+
270
+ // src/resources/channels.ts
271
+ function transformChannel(data) {
272
+ return {
273
+ id: data.id,
274
+ tenantId: data.tenant_id,
275
+ name: data.name,
276
+ description: data.description,
277
+ adapterType: data.adapter_type,
278
+ direction: data.direction,
279
+ status: data.status,
280
+ createdAt: data.created_at,
281
+ updatedAt: data.updated_at
282
+ };
283
+ }
284
+ var ChannelsResource = class {
285
+ constructor(http) {
286
+ this.http = http;
287
+ }
288
+ /**
289
+ * List all channels
290
+ */
291
+ async list() {
292
+ const response = await this.http.get("/v1/channels");
293
+ return {
294
+ data: response.channels.map(transformChannel),
295
+ total: response.total,
296
+ hasMore: false
297
+ };
298
+ }
299
+ /**
300
+ * Get a channel by ID
301
+ */
302
+ async get(channelId) {
303
+ const response = await this.http.get(`/v1/channels/${channelId}`);
304
+ return transformChannel(response.channel);
305
+ }
306
+ /**
307
+ * Create a new channel
308
+ * @returns The created channel and optionally an OAuth URL for OAuth-based adapters
309
+ */
310
+ async create(params) {
311
+ const response = await this.http.post("/v1/channels", {
312
+ name: params.name,
313
+ description: params.description,
314
+ adapter_type: params.adapterType,
315
+ direction: params.direction,
316
+ config: params.config
317
+ });
318
+ return {
319
+ channel: transformChannel(response.channel),
320
+ oauthUrl: response.oauth_url
321
+ };
322
+ }
323
+ /**
324
+ * Update a channel
325
+ */
326
+ async update(channelId, params) {
327
+ const response = await this.http.put(`/v1/channels/${channelId}`, {
328
+ name: params.name,
329
+ description: params.description,
330
+ status: params.status,
331
+ config: params.config
332
+ });
333
+ return transformChannel(response.channel);
334
+ }
335
+ /**
336
+ * Delete a channel
337
+ */
338
+ async delete(channelId) {
339
+ await this.http.delete(`/v1/channels/${channelId}`);
340
+ }
341
+ /**
342
+ * Test channel connectivity
343
+ */
344
+ async test(channelId) {
345
+ return this.http.post(`/v1/channels/${channelId}/test`);
346
+ }
347
+ /**
348
+ * Get channel health metrics
349
+ */
350
+ async health(channelId) {
351
+ const response = await this.http.get(`/v1/channels/${channelId}/health`);
352
+ return {
353
+ status: response.status,
354
+ lastEventAt: response.last_event_at,
355
+ errorCount24h: response.error_count_24h,
356
+ successRate: response.success_rate
357
+ };
358
+ }
359
+ };
360
+
361
+ // src/resources/events.ts
362
+ function transformEvent(data) {
363
+ return {
364
+ eventId: data.event_id,
365
+ tenantId: data.tenant_id,
366
+ channelId: data.channel_id,
367
+ eventType: data.event_type,
368
+ canonicalType: data.canonical_type,
369
+ direction: data.direction,
370
+ adapterType: data.adapter_type,
371
+ occurredAt: data.occurred_at,
372
+ ingestedAt: data.ingested_at,
373
+ payload: data.payload
374
+ };
375
+ }
376
+ var EventsResource = class {
377
+ constructor(http) {
378
+ this.http = http;
379
+ }
380
+ /**
381
+ * List activity events with optional filters
382
+ */
383
+ async list(params = {}) {
384
+ const query = {
385
+ limit: params.limit,
386
+ offset: params.offset,
387
+ channel_id: params.channelId,
388
+ event_type: params.eventType,
389
+ canonical_type: params.canonicalType,
390
+ direction: params.direction
391
+ };
392
+ if (params.startDate) {
393
+ query.start_date = params.startDate instanceof Date ? params.startDate.toISOString() : params.startDate;
394
+ }
395
+ if (params.endDate) {
396
+ query.end_date = params.endDate instanceof Date ? params.endDate.toISOString() : params.endDate;
397
+ }
398
+ const response = await this.http.get("/v1/events", query);
399
+ return {
400
+ data: response.events.map(transformEvent),
401
+ total: response.total,
402
+ hasMore: response.next_offset !== void 0,
403
+ nextOffset: response.next_offset
404
+ };
405
+ }
406
+ /**
407
+ * Get a single event by ID
408
+ */
409
+ async get(eventId) {
410
+ const response = await this.http.get(`/v1/events/${eventId}`);
411
+ return transformEvent(response);
412
+ }
413
+ /**
414
+ * Get event statistics summary
415
+ */
416
+ async stats(options = {}) {
417
+ const response = await this.http.get("/v1/events/stats/summary", {
418
+ days: options.days || 7
419
+ });
420
+ return {
421
+ totalEvents: response.total_events,
422
+ eventsByType: response.events_by_type,
423
+ eventsByChannel: response.events_by_channel
424
+ };
425
+ }
426
+ /**
427
+ * Get time series data for charts
428
+ */
429
+ async timeseries(options = {}) {
430
+ const response = await this.http.get("/v1/events/stats/timeseries", {
431
+ days: options.days || 7,
432
+ granularity: options.granularity || "hour"
433
+ });
434
+ return response.data;
435
+ }
436
+ };
437
+
438
+ // src/resources/messages.ts
439
+ var MessagesResource = class {
440
+ constructor(http) {
441
+ this.http = http;
442
+ }
443
+ /**
444
+ * Send a message through a channel
445
+ *
446
+ * @example
447
+ * ```typescript
448
+ * // Send an SMS
449
+ * const result = await veroai.messages.send({
450
+ * channelId: 'ch_abc123',
451
+ * to: '+15551234567',
452
+ * content: { type: 'text', text: 'Hello from VeroAI!' }
453
+ * });
454
+ *
455
+ * // Send an email
456
+ * const result = await veroai.messages.send({
457
+ * channelId: 'ch_def456',
458
+ * to: 'user@example.com',
459
+ * subject: 'Welcome!',
460
+ * content: {
461
+ * type: 'html',
462
+ * html: '<h1>Welcome to our platform</h1>'
463
+ * }
464
+ * });
465
+ * ```
466
+ */
467
+ async send(params) {
468
+ const response = await this.http.post("/v1/messages", {
469
+ channel_id: params.channelId,
470
+ to: params.to,
471
+ subject: params.subject,
472
+ content: params.content,
473
+ metadata: params.metadata
474
+ });
475
+ return {
476
+ messageId: response.message_id,
477
+ eventId: response.event_id,
478
+ status: response.status,
479
+ providerMessageId: response.provider_message_id
480
+ };
481
+ }
482
+ /**
483
+ * Send a message to multiple recipients (batch)
484
+ *
485
+ * @example
486
+ * ```typescript
487
+ * const results = await veroai.messages.sendBatch({
488
+ * channelId: 'ch_abc123',
489
+ * messages: [
490
+ * { to: '+15551234567', content: { type: 'text', text: 'Hello!' } },
491
+ * { to: '+15559876543', content: { type: 'text', text: 'Hi there!' } },
492
+ * ]
493
+ * });
494
+ * ```
495
+ */
496
+ async sendBatch(params) {
497
+ const results = [];
498
+ const batchSize = 100;
499
+ for (let i = 0; i < params.messages.length; i += batchSize) {
500
+ const batch = params.messages.slice(i, i + batchSize);
501
+ const batchResults = await Promise.all(
502
+ batch.map(
503
+ (msg) => this.send({
504
+ channelId: params.channelId,
505
+ to: msg.to,
506
+ subject: msg.subject,
507
+ content: msg.content,
508
+ metadata: msg.metadata
509
+ })
510
+ )
511
+ );
512
+ results.push(...batchResults);
513
+ }
514
+ return results;
515
+ }
516
+ };
517
+
518
+ // src/resources/webhooks.ts
519
+ function transformWebhook(data) {
520
+ return {
521
+ id: data.id,
522
+ tenantId: data.tenant_id,
523
+ name: data.name,
524
+ url: data.url,
525
+ events: data.events,
526
+ channelId: data.channel_id,
527
+ headers: data.headers,
528
+ status: data.status,
529
+ retryConfig: {
530
+ enabled: data.retry_config?.enabled,
531
+ maxAttempts: data.retry_config?.max_attempts,
532
+ backoff: data.retry_config?.backoff
533
+ },
534
+ createdAt: data.created_at,
535
+ updatedAt: data.updated_at
536
+ };
537
+ }
538
+ function transformDelivery(data) {
539
+ return {
540
+ id: data.id,
541
+ webhookId: data.webhook_id,
542
+ eventId: data.event_id,
543
+ eventType: data.event_type,
544
+ status: data.status,
545
+ attempts: data.attempts,
546
+ responseCode: data.response_code,
547
+ responseBody: data.response_body,
548
+ responseTimeMs: data.response_time_ms,
549
+ createdAt: data.created_at,
550
+ completedAt: data.completed_at
551
+ };
552
+ }
553
+ var WebhooksResource = class {
554
+ constructor(http) {
555
+ this.http = http;
556
+ }
557
+ /**
558
+ * List all webhooks
559
+ */
560
+ async list() {
561
+ const response = await this.http.get("/v1/webhooks");
562
+ return {
563
+ data: response.webhooks.map(transformWebhook),
564
+ total: response.total,
565
+ hasMore: false
566
+ };
567
+ }
568
+ /**
569
+ * Get a webhook by ID
570
+ */
571
+ async get(webhookId) {
572
+ const response = await this.http.get(`/v1/webhooks/${webhookId}`);
573
+ return transformWebhook(response.webhook);
574
+ }
575
+ /**
576
+ * Create a new webhook
577
+ * @returns The created webhook and the signing secret (only returned once)
578
+ */
579
+ async create(params) {
580
+ const response = await this.http.post("/v1/webhooks", {
581
+ name: params.name,
582
+ url: params.url,
583
+ events: params.events,
584
+ channel_id: params.channelId,
585
+ headers: params.headers,
586
+ retry_config: params.retryConfig ? {
587
+ enabled: params.retryConfig.enabled ?? true,
588
+ max_attempts: params.retryConfig.maxAttempts ?? 5,
589
+ backoff: params.retryConfig.backoff ?? "exponential"
590
+ } : void 0
591
+ });
592
+ return {
593
+ webhook: transformWebhook(response.webhook),
594
+ secret: response.secret
595
+ };
596
+ }
597
+ /**
598
+ * Update a webhook
599
+ */
600
+ async update(webhookId, params) {
601
+ const response = await this.http.patch(`/v1/webhooks/${webhookId}`, {
602
+ name: params.name,
603
+ url: params.url,
604
+ events: params.events,
605
+ channel_id: params.channelId,
606
+ headers: params.headers,
607
+ status: params.status,
608
+ retry_config: params.retryConfig ? {
609
+ enabled: params.retryConfig.enabled,
610
+ max_attempts: params.retryConfig.maxAttempts,
611
+ backoff: params.retryConfig.backoff
612
+ } : void 0
613
+ });
614
+ return transformWebhook(response.webhook);
615
+ }
616
+ /**
617
+ * Delete a webhook
618
+ */
619
+ async delete(webhookId) {
620
+ await this.http.delete(`/v1/webhooks/${webhookId}`);
621
+ }
622
+ /**
623
+ * Regenerate webhook signing secret
624
+ * @returns The new signing secret (only returned once)
625
+ */
626
+ async regenerateSecret(webhookId) {
627
+ const response = await this.http.post(
628
+ `/v1/webhooks/${webhookId}/regenerate-secret`
629
+ );
630
+ return {
631
+ webhook: transformWebhook(response.webhook),
632
+ secret: response.secret
633
+ };
634
+ }
635
+ /**
636
+ * List delivery history for a webhook
637
+ */
638
+ async deliveries(webhookId, options = {}) {
639
+ const response = await this.http.get(
640
+ `/v1/webhooks/${webhookId}/deliveries`,
641
+ {
642
+ limit: options.limit || 50,
643
+ cursor: options.cursor
644
+ }
645
+ );
646
+ return {
647
+ data: response.deliveries.map(transformDelivery),
648
+ total: response.total,
649
+ hasMore: response.has_more,
650
+ nextCursor: response.next_cursor
651
+ };
652
+ }
653
+ /**
654
+ * Get webhook delivery statistics
655
+ */
656
+ async stats(webhookId, options = {}) {
657
+ const response = await this.http.get(
658
+ `/v1/webhooks/${webhookId}/stats`,
659
+ {
660
+ time_range: options.timeRange || "24h"
661
+ }
662
+ );
663
+ return {
664
+ total: response.total,
665
+ success: response.success,
666
+ failed: response.failed,
667
+ pending: response.pending,
668
+ successRate: response.success_rate,
669
+ averageResponseTimeMs: response.average_response_time_ms,
670
+ timeRange: response.time_range
671
+ };
672
+ }
673
+ };
674
+
675
+ // src/resources/api-keys.ts
676
+ function transformApiKey(data) {
677
+ return {
678
+ id: data.id,
679
+ tenantId: data.tenant_id,
680
+ name: data.name,
681
+ keyPrefix: data.key_prefix,
682
+ environment: data.environment,
683
+ scopes: data.scopes,
684
+ expiresAt: data.expires_at,
685
+ lastUsedAt: data.last_used_at,
686
+ createdAt: data.created_at
687
+ };
688
+ }
689
+ var ApiKeysResource = class {
690
+ constructor(http) {
691
+ this.http = http;
692
+ }
693
+ /**
694
+ * List all API keys
695
+ */
696
+ async list() {
697
+ const response = await this.http.get("/v1/api-keys");
698
+ return {
699
+ data: response.api_keys.map(transformApiKey),
700
+ total: response.total,
701
+ hasMore: false
702
+ };
703
+ }
704
+ /**
705
+ * Get an API key by ID
706
+ */
707
+ async get(keyId) {
708
+ const response = await this.http.get(`/v1/api-keys/${keyId}`);
709
+ return transformApiKey(response.api_key);
710
+ }
711
+ /**
712
+ * Create a new API key
713
+ * @returns The created API key and the plaintext key (only returned once)
714
+ *
715
+ * @example
716
+ * ```typescript
717
+ * const { apiKey, key } = await veroai.apiKeys.create({
718
+ * name: 'Production Key',
719
+ * environment: 'production',
720
+ * scopes: ['channels:read', 'channels:write', 'messages:send'],
721
+ * });
722
+ *
723
+ * // Save this key securely - it won't be shown again!
724
+ * console.log('API Key:', key); // sk_live_abc123...
725
+ * ```
726
+ */
727
+ async create(params) {
728
+ const response = await this.http.post("/v1/api-keys", {
729
+ name: params.name,
730
+ environment: params.environment,
731
+ scopes: params.scopes,
732
+ expires_at: params.expiresAt instanceof Date ? params.expiresAt.toISOString() : params.expiresAt
733
+ });
734
+ return {
735
+ apiKey: transformApiKey(response.api_key),
736
+ key: response.key
737
+ };
738
+ }
739
+ /**
740
+ * Delete (revoke) an API key
741
+ */
742
+ async delete(keyId) {
743
+ await this.http.delete(`/v1/api-keys/${keyId}`);
744
+ }
745
+ /**
746
+ * Alias for delete - revoke an API key
747
+ */
748
+ async revoke(keyId) {
749
+ return this.delete(keyId);
750
+ }
751
+ };
752
+
753
+ // src/resources/domains.ts
754
+ function transformDomain(data) {
755
+ return {
756
+ id: data.id,
757
+ tenantId: data.tenant_id,
758
+ domain: data.domain,
759
+ status: data.status,
760
+ verificationRecord: data.verification_record,
761
+ verificationStatus: {
762
+ dkim: data.verification_status.dkim,
763
+ spf: data.verification_status.spf,
764
+ dmarc: data.verification_status.dmarc,
765
+ mx: data.verification_status.mx,
766
+ lastCheckedAt: data.verification_status.last_checked_at
767
+ },
768
+ dnsRecords: data.dns_records.map((record) => ({
769
+ type: record.type,
770
+ name: record.name,
771
+ value: record.value,
772
+ priority: record.priority,
773
+ verified: record.verified
774
+ })),
775
+ createdAt: data.created_at,
776
+ updatedAt: data.updated_at
777
+ };
778
+ }
779
+ var DomainsResource = class {
780
+ constructor(http) {
781
+ this.http = http;
782
+ }
783
+ /**
784
+ * List all domains
785
+ */
786
+ async list() {
787
+ const response = await this.http.get("/v1/domains");
788
+ return {
789
+ data: response.domains.map(transformDomain),
790
+ total: response.total,
791
+ hasMore: false
792
+ };
793
+ }
794
+ /**
795
+ * Get a domain by ID
796
+ */
797
+ async get(domainId) {
798
+ const response = await this.http.get(`/v1/domains/${domainId}`);
799
+ return transformDomain(response.domain);
800
+ }
801
+ /**
802
+ * Add a new domain
803
+ *
804
+ * @example
805
+ * ```typescript
806
+ * // Manual DNS verification
807
+ * const { domain } = await veroai.domains.create({
808
+ * domain: 'example.com',
809
+ * verificationMethod: 'manual',
810
+ * });
811
+ *
812
+ * // Automatic via Cloudflare
813
+ * const { domain } = await veroai.domains.create({
814
+ * domain: 'example.com',
815
+ * verificationMethod: 'cloudflare',
816
+ * cloudflareApiToken: 'your_cf_token',
817
+ * });
818
+ * ```
819
+ */
820
+ async create(params) {
821
+ const response = await this.http.post("/v1/domains", {
822
+ domain: params.domain,
823
+ verification_method: params.verificationMethod,
824
+ cloudflare_api_token: params.cloudflareApiToken
825
+ });
826
+ return {
827
+ domain: transformDomain(response.domain),
828
+ verificationRecord: response.verification_record
829
+ };
830
+ }
831
+ /**
832
+ * Delete a domain
833
+ */
834
+ async delete(domainId) {
835
+ await this.http.delete(`/v1/domains/${domainId}`);
836
+ }
837
+ /**
838
+ * Verify domain DNS records
839
+ */
840
+ async verify(domainId) {
841
+ const response = await this.http.post(
842
+ `/v1/domains/${domainId}/verify`
843
+ );
844
+ return {
845
+ domain: transformDomain(response.domain),
846
+ verificationResults: response.verification_results
847
+ };
848
+ }
849
+ /**
850
+ * Get DNS records that need to be configured
851
+ */
852
+ async dnsRecords(domainId) {
853
+ const domain = await this.get(domainId);
854
+ return domain.dnsRecords;
855
+ }
856
+ };
857
+
858
+ // src/resources/voice/numbers.ts
859
+ function transformPhoneNumber(data) {
860
+ return {
861
+ id: data.id,
862
+ number: data.number,
863
+ country: data.country,
864
+ region: data.region,
865
+ locality: data.locality,
866
+ capabilities: data.capabilities,
867
+ channelId: data.channel_id,
868
+ channelName: data.channel_name,
869
+ status: data.status,
870
+ monthlyCostCents: data.monthly_cost_cents,
871
+ setupCostCents: data.setup_cost_cents,
872
+ createdAt: data.created_at,
873
+ updatedAt: data.updated_at
874
+ };
875
+ }
876
+ function transformAvailableNumber(data) {
877
+ return {
878
+ number: data.number,
879
+ country: data.country,
880
+ region: data.region,
881
+ locality: data.locality,
882
+ capabilities: data.capabilities,
883
+ monthlyCostCents: data.monthly_cost_cents,
884
+ setupCostCents: data.setup_cost_cents,
885
+ provider: data.provider
886
+ };
887
+ }
888
+ var VoiceNumbersResource = class {
889
+ constructor(http) {
890
+ this.http = http;
891
+ }
892
+ /**
893
+ * Search for available phone numbers to purchase
894
+ */
895
+ async search(params) {
896
+ const response = await this.http.get("/v1/voice/numbers/search", {
897
+ country: params.country,
898
+ area_code: params.areaCode,
899
+ contains: params.contains,
900
+ capabilities: params.capabilities?.join(","),
901
+ limit: params.limit
902
+ });
903
+ return response.available_numbers.map(transformAvailableNumber);
904
+ }
905
+ /**
906
+ * Purchase a phone number
907
+ */
908
+ async purchase(params) {
909
+ const response = await this.http.post("/v1/voice/numbers/purchase", {
910
+ number: params.number,
911
+ channel_id: params.channelId
912
+ });
913
+ return transformPhoneNumber(response.number);
914
+ }
915
+ /**
916
+ * List owned phone numbers
917
+ */
918
+ async list(params) {
919
+ const response = await this.http.get("/v1/voice/numbers", {
920
+ channel_id: params?.channelId,
921
+ status: params?.status,
922
+ country: params?.country,
923
+ capabilities: params?.capabilities?.join(","),
924
+ limit: params?.limit,
925
+ offset: params?.offset
926
+ });
927
+ return {
928
+ data: response.numbers.map(transformPhoneNumber),
929
+ total: response.total,
930
+ hasMore: response.offset + response.numbers.length < response.total,
931
+ nextOffset: response.offset + response.numbers.length
932
+ };
933
+ }
934
+ /**
935
+ * Get a phone number by ID
936
+ */
937
+ async get(numberId) {
938
+ const response = await this.http.get(`/v1/voice/numbers/${numberId}`);
939
+ return transformPhoneNumber(response);
940
+ }
941
+ /**
942
+ * Update a phone number (assign/unassign to channel)
943
+ */
944
+ async update(numberId, params) {
945
+ const response = await this.http.patch(`/v1/voice/numbers/${numberId}`, {
946
+ channel_id: params.channelId
947
+ });
948
+ return transformPhoneNumber(response.number);
949
+ }
950
+ /**
951
+ * Release a phone number
952
+ */
953
+ async release(numberId) {
954
+ await this.http.delete(`/v1/voice/numbers/${numberId}`);
955
+ }
956
+ /**
957
+ * Assign a phone number to a channel
958
+ */
959
+ async assignToChannel(numberId, channelId) {
960
+ return this.update(numberId, { channelId });
961
+ }
962
+ /**
963
+ * Unassign a phone number from its channel
964
+ */
965
+ async unassignFromChannel(numberId) {
966
+ return this.update(numberId, { channelId: null });
967
+ }
968
+ };
969
+
970
+ // src/resources/voice/calls.ts
971
+ function transformCall(data) {
972
+ return {
973
+ id: data.id,
974
+ channelId: data.channel_id,
975
+ providerCallSid: data.provider_call_sid,
976
+ fromNumber: data.from_number,
977
+ toNumber: data.to_number,
978
+ direction: data.direction,
979
+ status: data.status,
980
+ endReason: data.end_reason,
981
+ initiatedAt: data.initiated_at,
982
+ ringingAt: data.ringing_at,
983
+ answeredAt: data.answered_at,
984
+ endedAt: data.ended_at,
985
+ durationSeconds: data.duration_seconds,
986
+ recordingUrl: data.recording_url,
987
+ transcriptionUrl: data.transcription_url,
988
+ agentId: data.agent_id,
989
+ metadata: data.metadata
990
+ };
991
+ }
992
+ var VoiceCallsResource = class {
993
+ constructor(http) {
994
+ this.http = http;
995
+ }
996
+ /**
997
+ * Initiate an outbound call
998
+ */
999
+ async dial(params) {
1000
+ const response = await this.http.post("/v1/voice/calls", {
1001
+ channel_id: params.channelId,
1002
+ to: params.to,
1003
+ from: params.from,
1004
+ timeout: params.timeout,
1005
+ metadata: params.metadata
1006
+ });
1007
+ return transformCall(response.call);
1008
+ }
1009
+ /**
1010
+ * List calls
1011
+ */
1012
+ async list(params) {
1013
+ const response = await this.http.get("/v1/voice/calls", {
1014
+ channel_id: params?.channelId,
1015
+ direction: params?.direction,
1016
+ status: params?.status,
1017
+ from_number: params?.fromNumber,
1018
+ to_number: params?.toNumber,
1019
+ start_date: params?.startDate instanceof Date ? params.startDate.toISOString() : params?.startDate,
1020
+ end_date: params?.endDate instanceof Date ? params.endDate.toISOString() : params?.endDate,
1021
+ limit: params?.limit,
1022
+ offset: params?.offset
1023
+ });
1024
+ return {
1025
+ data: response.calls.map(transformCall),
1026
+ total: response.total,
1027
+ hasMore: response.offset + response.calls.length < response.total,
1028
+ nextOffset: response.offset + response.calls.length
1029
+ };
1030
+ }
1031
+ /**
1032
+ * Get a call by ID
1033
+ */
1034
+ async get(callId) {
1035
+ const response = await this.http.get(`/v1/voice/calls/${callId}`);
1036
+ return transformCall(response);
1037
+ }
1038
+ /**
1039
+ * Hang up an active call
1040
+ */
1041
+ async hangup(callId) {
1042
+ await this.http.post(`/v1/voice/calls/${callId}/hangup`);
1043
+ }
1044
+ };
1045
+
1046
+ // src/resources/voice/rooms.ts
1047
+ var VoiceRoomsResource = class {
1048
+ constructor(http) {
1049
+ this.http = http;
1050
+ }
1051
+ /**
1052
+ * Create a new WebRTC room
1053
+ *
1054
+ * @example
1055
+ * ```typescript
1056
+ * const roomInfo = await veroai.voice.rooms.create({
1057
+ * name: 'support-call-123',
1058
+ * emptyTimeout: 300,
1059
+ * maxParticipants: 2,
1060
+ * });
1061
+ * // Connect to room using roomInfo.wsUrl and roomInfo.token
1062
+ * ```
1063
+ */
1064
+ async create(params) {
1065
+ const response = await this.http.post("/voice/rooms", {
1066
+ name: params.name,
1067
+ empty_timeout: params.emptyTimeout,
1068
+ max_participants: params.maxParticipants,
1069
+ metadata: params.metadata
1070
+ });
1071
+ return {
1072
+ sid: response.room.id,
1073
+ name: response.room.name,
1074
+ wsUrl: response.room.ws_url,
1075
+ token: response.room.token,
1076
+ numParticipants: 0,
1077
+ metadata: params.metadata
1078
+ };
1079
+ }
1080
+ /**
1081
+ * Join an existing room or create and join if it doesn't exist
1082
+ *
1083
+ * @example
1084
+ * ```typescript
1085
+ * const roomInfo = await veroai.voice.rooms.join({
1086
+ * roomName: 'support-call-123',
1087
+ * participantName: 'Agent Smith',
1088
+ * });
1089
+ * // Use roomInfo.token to connect via LiveKit client SDK
1090
+ * ```
1091
+ */
1092
+ async join(params) {
1093
+ const response = await this.http.post(
1094
+ `/voice/rooms/${encodeURIComponent(params.roomName)}/join`,
1095
+ {
1096
+ participant_name: params.participantName,
1097
+ can_publish: params.canPublish,
1098
+ can_subscribe: params.canSubscribe,
1099
+ metadata: params.metadata
1100
+ }
1101
+ );
1102
+ return {
1103
+ sid: "",
1104
+ name: response.room_name,
1105
+ wsUrl: response.ws_url,
1106
+ token: response.token,
1107
+ numParticipants: 0
1108
+ };
1109
+ }
1110
+ /**
1111
+ * Get room details
1112
+ *
1113
+ * @example
1114
+ * ```typescript
1115
+ * const room = await veroai.voice.rooms.get('support-call-123');
1116
+ * console.log(`Room: ${room.name}`);
1117
+ * ```
1118
+ */
1119
+ async get(roomName) {
1120
+ const response = await this.http.get(
1121
+ `/voice/rooms/${encodeURIComponent(roomName)}`
1122
+ );
1123
+ return {
1124
+ sid: "",
1125
+ name: response.room.name,
1126
+ emptyTimeout: 300,
1127
+ maxParticipants: 10,
1128
+ creationTime: "",
1129
+ numParticipants: 0
1130
+ };
1131
+ }
1132
+ /**
1133
+ * List all active rooms
1134
+ *
1135
+ * @example
1136
+ * ```typescript
1137
+ * const rooms = await veroai.voice.rooms.list();
1138
+ * for (const room of rooms) {
1139
+ * console.log(`${room.name}`);
1140
+ * }
1141
+ * ```
1142
+ */
1143
+ async list(params) {
1144
+ const searchParams = new URLSearchParams();
1145
+ if (params?.names) {
1146
+ for (const name of params.names) {
1147
+ searchParams.append("names", name);
1148
+ }
1149
+ }
1150
+ const query = searchParams.toString();
1151
+ const response = await this.http.get(
1152
+ `/voice/rooms${query ? `?${query}` : ""}`
1153
+ );
1154
+ return response.rooms.map((room) => ({
1155
+ sid: "",
1156
+ name: room.name,
1157
+ emptyTimeout: 300,
1158
+ maxParticipants: 10,
1159
+ creationTime: "",
1160
+ numParticipants: 0
1161
+ }));
1162
+ }
1163
+ /**
1164
+ * Delete a room and disconnect all participants
1165
+ *
1166
+ * @example
1167
+ * ```typescript
1168
+ * await veroai.voice.rooms.delete('support-call-123');
1169
+ * ```
1170
+ */
1171
+ async delete(roomName) {
1172
+ await this.http.delete(`/voice/rooms/${encodeURIComponent(roomName)}`);
1173
+ }
1174
+ /**
1175
+ * List participants in a room
1176
+ *
1177
+ * @example
1178
+ * ```typescript
1179
+ * const participants = await veroai.voice.rooms.listParticipants('support-call-123');
1180
+ * for (const p of participants) {
1181
+ * console.log(`${p.name} (${p.state})`);
1182
+ * }
1183
+ * ```
1184
+ */
1185
+ async listParticipants(roomName) {
1186
+ return this.http.get(
1187
+ `/voice/rooms/${encodeURIComponent(roomName)}/participants`
1188
+ );
1189
+ }
1190
+ /**
1191
+ * Remove a participant from a room
1192
+ *
1193
+ * @example
1194
+ * ```typescript
1195
+ * await veroai.voice.rooms.removeParticipant('support-call-123', 'user-456');
1196
+ * ```
1197
+ */
1198
+ async removeParticipant(roomName, identity) {
1199
+ await this.http.delete(
1200
+ `/voice/rooms/${encodeURIComponent(roomName)}/participants/${encodeURIComponent(identity)}`
1201
+ );
1202
+ }
1203
+ /**
1204
+ * Mute or unmute a participant's audio
1205
+ *
1206
+ * @example
1207
+ * ```typescript
1208
+ * // Mute participant
1209
+ * await veroai.voice.rooms.muteParticipant('support-call-123', 'user-456', true);
1210
+ *
1211
+ * // Unmute participant
1212
+ * await veroai.voice.rooms.muteParticipant('support-call-123', 'user-456', false);
1213
+ * ```
1214
+ */
1215
+ async muteParticipant(roomName, identity, muted) {
1216
+ await this.http.post(
1217
+ `/voice/rooms/${encodeURIComponent(roomName)}/participants/${encodeURIComponent(identity)}/mute`,
1218
+ { muted }
1219
+ );
1220
+ }
1221
+ /**
1222
+ * Send a data message to participants in a room
1223
+ *
1224
+ * @example
1225
+ * ```typescript
1226
+ * // Send to all participants
1227
+ * await veroai.voice.rooms.sendData('support-call-123', { type: 'notification', message: 'Recording started' });
1228
+ *
1229
+ * // Send to specific participants
1230
+ * await veroai.voice.rooms.sendData('support-call-123', { type: 'private' }, ['user-456']);
1231
+ * ```
1232
+ */
1233
+ async sendData(roomName, data, destinationIdentities) {
1234
+ await this.http.post(`/voice/rooms/${encodeURIComponent(roomName)}/data`, {
1235
+ data,
1236
+ destinationIdentities
1237
+ });
1238
+ }
1239
+ };
1240
+
1241
+ // src/resources/voice/index.ts
1242
+ var VoiceResource = class {
1243
+ /**
1244
+ * Phone number management
1245
+ */
1246
+ numbers;
1247
+ /**
1248
+ * Call management
1249
+ */
1250
+ calls;
1251
+ /**
1252
+ * LiveKit WebRTC room management for browser-based voice/video calls
1253
+ */
1254
+ rooms;
1255
+ constructor(http) {
1256
+ this.numbers = new VoiceNumbersResource(http);
1257
+ this.calls = new VoiceCallsResource(http);
1258
+ this.rooms = new VoiceRoomsResource(http);
1259
+ }
1260
+ };
1261
+
1262
+ // src/resources/agents.ts
1263
+ function transformAgent(agent) {
1264
+ return {
1265
+ id: agent.id,
1266
+ name: agent.name,
1267
+ description: agent.description,
1268
+ enabled: agent.enabled,
1269
+ modelConfig: {
1270
+ provider: agent.model_config.provider,
1271
+ modelId: agent.model_config.model_id,
1272
+ temperature: agent.model_config.temperature,
1273
+ maxTokens: agent.model_config.max_tokens
1274
+ },
1275
+ systemPrompt: agent.system_prompt,
1276
+ status: agent.status
1277
+ };
1278
+ }
1279
+ var AgentsResource = class {
1280
+ constructor(http) {
1281
+ this.http = http;
1282
+ }
1283
+ /**
1284
+ * List AI agents
1285
+ *
1286
+ * @example
1287
+ * ```typescript
1288
+ * const agents = await veroai.agents.list({ status: 'active' });
1289
+ * for (const agent of agents.data) {
1290
+ * console.log(`${agent.name} (${agent.modelConfig.provider})`);
1291
+ * }
1292
+ * ```
1293
+ */
1294
+ async list(params) {
1295
+ const searchParams = new URLSearchParams();
1296
+ if (params?.status) searchParams.set("status", params.status);
1297
+ if (params?.enabled !== void 0) searchParams.set("enabled", String(params.enabled));
1298
+ if (params?.limit) searchParams.set("limit", String(params.limit));
1299
+ if (params?.offset) searchParams.set("offset", String(params.offset));
1300
+ const query = searchParams.toString();
1301
+ const response = await this.http.get(
1302
+ `/agents${query ? `?${query}` : ""}`
1303
+ );
1304
+ return {
1305
+ data: response.agents.map(transformAgent),
1306
+ total: response.total,
1307
+ hasMore: response.offset + response.agents.length < response.total,
1308
+ nextOffset: response.offset + response.agents.length < response.total ? response.offset + response.limit : void 0
1309
+ };
1310
+ }
1311
+ /**
1312
+ * Get an agent by ID
1313
+ *
1314
+ * @example
1315
+ * ```typescript
1316
+ * const agent = await veroai.agents.get('agent_123');
1317
+ * console.log(`System prompt: ${agent.systemPrompt}`);
1318
+ * ```
1319
+ */
1320
+ async get(agentId) {
1321
+ const response = await this.http.get(
1322
+ `/agents/${encodeURIComponent(agentId)}`
1323
+ );
1324
+ return transformAgent(response.agent);
1325
+ }
1326
+ /**
1327
+ * Create a new AI agent
1328
+ *
1329
+ * @example
1330
+ * ```typescript
1331
+ * const agent = await veroai.agents.create({
1332
+ * name: 'Support Agent',
1333
+ * modelConfig: {
1334
+ * provider: 'anthropic',
1335
+ * modelId: 'claude-3-5-sonnet-20241022',
1336
+ * temperature: 0.7,
1337
+ * },
1338
+ * systemPrompt: 'You are a helpful support agent...',
1339
+ * enabled: true,
1340
+ * });
1341
+ * ```
1342
+ */
1343
+ async create(params) {
1344
+ const response = await this.http.post("/agents", {
1345
+ name: params.name,
1346
+ description: params.description,
1347
+ model_config: {
1348
+ provider: params.modelConfig.provider,
1349
+ model_id: params.modelConfig.modelId,
1350
+ temperature: params.modelConfig.temperature ?? 0.7,
1351
+ max_tokens: params.modelConfig.maxTokens ?? 4096
1352
+ },
1353
+ system_prompt: params.systemPrompt,
1354
+ enabled: params.enabled ?? false
1355
+ });
1356
+ return transformAgent(response.agent);
1357
+ }
1358
+ /**
1359
+ * Update an agent
1360
+ *
1361
+ * @example
1362
+ * ```typescript
1363
+ * const agent = await veroai.agents.update('agent_123', {
1364
+ * systemPrompt: 'Updated prompt...',
1365
+ * enabled: true,
1366
+ * });
1367
+ * ```
1368
+ */
1369
+ async update(agentId, params) {
1370
+ const body = {};
1371
+ if (params.name !== void 0) body.name = params.name;
1372
+ if (params.description !== void 0) body.description = params.description;
1373
+ if (params.systemPrompt !== void 0) body.system_prompt = params.systemPrompt;
1374
+ if (params.enabled !== void 0) body.enabled = params.enabled;
1375
+ if (params.status !== void 0) body.status = params.status;
1376
+ if (params.modelConfig) {
1377
+ body.model_config = {
1378
+ ...params.modelConfig.provider && { provider: params.modelConfig.provider },
1379
+ ...params.modelConfig.modelId && { model_id: params.modelConfig.modelId },
1380
+ ...params.modelConfig.temperature !== void 0 && { temperature: params.modelConfig.temperature },
1381
+ ...params.modelConfig.maxTokens !== void 0 && { max_tokens: params.modelConfig.maxTokens }
1382
+ };
1383
+ }
1384
+ const response = await this.http.patch(
1385
+ `/agents/${encodeURIComponent(agentId)}`,
1386
+ body
1387
+ );
1388
+ return transformAgent(response.agent);
1389
+ }
1390
+ /**
1391
+ * Delete an agent
1392
+ *
1393
+ * @example
1394
+ * ```typescript
1395
+ * await veroai.agents.delete('agent_123');
1396
+ * ```
1397
+ */
1398
+ async delete(agentId) {
1399
+ await this.http.delete(`/agents/${encodeURIComponent(agentId)}`);
1400
+ }
1401
+ /**
1402
+ * Enable an agent
1403
+ *
1404
+ * @example
1405
+ * ```typescript
1406
+ * const agent = await veroai.agents.enable('agent_123');
1407
+ * ```
1408
+ */
1409
+ async enable(agentId) {
1410
+ return this.update(agentId, { enabled: true });
1411
+ }
1412
+ /**
1413
+ * Disable an agent
1414
+ *
1415
+ * @example
1416
+ * ```typescript
1417
+ * const agent = await veroai.agents.disable('agent_123');
1418
+ * ```
1419
+ */
1420
+ async disable(agentId) {
1421
+ return this.update(agentId, { enabled: false });
1422
+ }
1423
+ };
1424
+
1425
+ // src/realtime/realtime.ts
1426
+ var DEFAULT_REALTIME_URL = "wss://wss.veroai.dev/ws";
1427
+ var DEFAULT_RECONNECT_INTERVAL = 1e3;
1428
+ var MAX_RECONNECT_INTERVAL = 3e4;
1429
+ var DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;
1430
+ var DEFAULT_HEARTBEAT_INTERVAL = 3e4;
1431
+ function isBrowser() {
1432
+ return typeof window !== "undefined" && typeof window.WebSocket !== "undefined";
1433
+ }
1434
+ async function getWebSocket() {
1435
+ if (isBrowser()) {
1436
+ return window.WebSocket;
1437
+ }
1438
+ try {
1439
+ const ws = await import('ws');
1440
+ return ws.default || ws;
1441
+ } catch {
1442
+ throw new Error(
1443
+ 'WebSocket is not available. In Node.js, install the "ws" package: npm install ws'
1444
+ );
1445
+ }
1446
+ }
1447
+ var RealtimeResource = class {
1448
+ config;
1449
+ tokenFetcher;
1450
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1451
+ ws = null;
1452
+ state = "disconnected";
1453
+ reconnectAttempts = 0;
1454
+ reconnectTimeout = null;
1455
+ heartbeatInterval = null;
1456
+ // Event handlers
1457
+ eventHandlers = /* @__PURE__ */ new Set();
1458
+ stateHandlers = /* @__PURE__ */ new Set();
1459
+ errorHandlers = /* @__PURE__ */ new Set();
1460
+ // Active subscriptions for reconnection
1461
+ activeSubscriptions = {
1462
+ eventTypes: /* @__PURE__ */ new Set(),
1463
+ channels: /* @__PURE__ */ new Set(),
1464
+ subscribedToAll: false
1465
+ };
1466
+ // Pending subscription confirmations
1467
+ pendingSubscriptions = /* @__PURE__ */ new Map();
1468
+ constructor(tokenFetcher, config) {
1469
+ this.tokenFetcher = tokenFetcher;
1470
+ this.config = {
1471
+ url: config?.url ?? DEFAULT_REALTIME_URL,
1472
+ autoReconnect: config?.autoReconnect ?? true,
1473
+ reconnectInterval: config?.reconnectInterval ?? DEFAULT_RECONNECT_INTERVAL,
1474
+ maxReconnectAttempts: config?.maxReconnectAttempts ?? DEFAULT_MAX_RECONNECT_ATTEMPTS,
1475
+ heartbeatInterval: config?.heartbeatInterval ?? DEFAULT_HEARTBEAT_INTERVAL
1476
+ };
1477
+ }
1478
+ /**
1479
+ * Get current connection state
1480
+ */
1481
+ getState() {
1482
+ return this.state;
1483
+ }
1484
+ /**
1485
+ * Connect to the WebSocket server
1486
+ */
1487
+ async connect() {
1488
+ if (this.state === "connected" || this.state === "connecting") {
1489
+ return;
1490
+ }
1491
+ this.setState("connecting");
1492
+ return new Promise(async (resolve, reject) => {
1493
+ try {
1494
+ const token = await this.tokenFetcher();
1495
+ const WS = await getWebSocket();
1496
+ const url = new URL(this.config.url);
1497
+ url.searchParams.set("token", token);
1498
+ this.ws = new WS(url.toString());
1499
+ this.ws.onopen = () => {
1500
+ this.setState("connected");
1501
+ this.reconnectAttempts = 0;
1502
+ this.startHeartbeat();
1503
+ this.resubscribe();
1504
+ resolve();
1505
+ };
1506
+ this.ws.onclose = (event) => {
1507
+ this.stopHeartbeat();
1508
+ this.ws = null;
1509
+ if (this.state === "connecting") {
1510
+ reject(new Error(`Connection failed: ${event.reason || "Unknown reason"}`));
1511
+ this.setState("disconnected");
1512
+ return;
1513
+ }
1514
+ this.setState("disconnected");
1515
+ if (this.config.autoReconnect && this.shouldReconnect()) {
1516
+ this.scheduleReconnect();
1517
+ }
1518
+ };
1519
+ this.ws.onerror = (event) => {
1520
+ const error = new Error(
1521
+ "WebSocket error" + (event.message ? `: ${event.message}` : "")
1522
+ );
1523
+ this.emitError(error);
1524
+ if (this.state === "connecting") {
1525
+ reject(error);
1526
+ }
1527
+ };
1528
+ this.ws.onmessage = (event) => {
1529
+ this.handleMessage(event.data);
1530
+ };
1531
+ } catch (error) {
1532
+ this.setState("disconnected");
1533
+ reject(error);
1534
+ }
1535
+ });
1536
+ }
1537
+ /**
1538
+ * Disconnect from the WebSocket server
1539
+ */
1540
+ disconnect() {
1541
+ this.config.autoReconnect = false;
1542
+ this.clearReconnectTimeout();
1543
+ this.stopHeartbeat();
1544
+ if (this.ws) {
1545
+ this.ws.close(1e3, "Client disconnect");
1546
+ this.ws = null;
1547
+ }
1548
+ this.setState("disconnected");
1549
+ }
1550
+ /**
1551
+ * Subscribe to all events for the tenant
1552
+ */
1553
+ async subscribeAll() {
1554
+ this.activeSubscriptions.subscribedToAll = true;
1555
+ return this.sendSubscription({
1556
+ type: "subscribe",
1557
+ subscriptionType: "all"
1558
+ });
1559
+ }
1560
+ /**
1561
+ * Unsubscribe from all events
1562
+ */
1563
+ async unsubscribeAll() {
1564
+ this.activeSubscriptions.subscribedToAll = false;
1565
+ return this.sendSubscription({
1566
+ type: "unsubscribe",
1567
+ subscriptionType: "all"
1568
+ });
1569
+ }
1570
+ /**
1571
+ * Subscribe to specific channels
1572
+ */
1573
+ async subscribeChannels(channelIds) {
1574
+ for (const id of channelIds) {
1575
+ this.activeSubscriptions.channels.add(id);
1576
+ }
1577
+ return this.sendSubscription({
1578
+ type: "subscribe",
1579
+ subscriptionType: "channel",
1580
+ channels: channelIds
1581
+ });
1582
+ }
1583
+ /**
1584
+ * Unsubscribe from specific channels
1585
+ */
1586
+ async unsubscribeChannels(channelIds) {
1587
+ for (const id of channelIds) {
1588
+ this.activeSubscriptions.channels.delete(id);
1589
+ }
1590
+ return this.sendSubscription({
1591
+ type: "unsubscribe",
1592
+ subscriptionType: "channel",
1593
+ channels: channelIds
1594
+ });
1595
+ }
1596
+ /**
1597
+ * Subscribe to specific event types
1598
+ */
1599
+ async subscribeEventTypes(eventTypes) {
1600
+ for (const type of eventTypes) {
1601
+ this.activeSubscriptions.eventTypes.add(type);
1602
+ }
1603
+ return this.sendSubscription({
1604
+ type: "subscribe",
1605
+ subscriptionType: "event_type",
1606
+ eventTypes
1607
+ });
1608
+ }
1609
+ /**
1610
+ * Unsubscribe from specific event types
1611
+ */
1612
+ async unsubscribeEventTypes(eventTypes) {
1613
+ for (const type of eventTypes) {
1614
+ this.activeSubscriptions.eventTypes.delete(type);
1615
+ }
1616
+ return this.sendSubscription({
1617
+ type: "unsubscribe",
1618
+ subscriptionType: "event_type",
1619
+ eventTypes
1620
+ });
1621
+ }
1622
+ /**
1623
+ * Subscribe to channels and/or event types
1624
+ */
1625
+ async subscribe(options) {
1626
+ const promises = [];
1627
+ if (options.channels?.length) {
1628
+ promises.push(this.subscribeChannels(options.channels));
1629
+ }
1630
+ if (options.eventTypes?.length) {
1631
+ promises.push(this.subscribeEventTypes(options.eventTypes));
1632
+ }
1633
+ if (promises.length === 0) {
1634
+ throw new Error("Must specify at least one channel or event type");
1635
+ }
1636
+ await Promise.all(promises);
1637
+ }
1638
+ /**
1639
+ * Unsubscribe from channels and/or event types
1640
+ */
1641
+ async unsubscribe(options) {
1642
+ const promises = [];
1643
+ if (options.channels?.length) {
1644
+ promises.push(this.unsubscribeChannels(options.channels));
1645
+ }
1646
+ if (options.eventTypes?.length) {
1647
+ promises.push(this.unsubscribeEventTypes(options.eventTypes));
1648
+ }
1649
+ await Promise.all(promises);
1650
+ }
1651
+ /**
1652
+ * Add event handler
1653
+ */
1654
+ onEvent(handler) {
1655
+ this.eventHandlers.add(handler);
1656
+ return () => this.eventHandlers.delete(handler);
1657
+ }
1658
+ /**
1659
+ * Add connection state change handler
1660
+ */
1661
+ onStateChange(handler) {
1662
+ this.stateHandlers.add(handler);
1663
+ return () => this.stateHandlers.delete(handler);
1664
+ }
1665
+ /**
1666
+ * Add error handler
1667
+ */
1668
+ onError(handler) {
1669
+ this.errorHandlers.add(handler);
1670
+ return () => this.errorHandlers.delete(handler);
1671
+ }
1672
+ /**
1673
+ * Remove all handlers
1674
+ */
1675
+ removeAllHandlers() {
1676
+ this.eventHandlers.clear();
1677
+ this.stateHandlers.clear();
1678
+ this.errorHandlers.clear();
1679
+ }
1680
+ // Private methods
1681
+ setState(state) {
1682
+ if (this.state === state) return;
1683
+ this.state = state;
1684
+ for (const handler of this.stateHandlers) {
1685
+ try {
1686
+ handler(state);
1687
+ } catch (error) {
1688
+ console.error("State handler error:", error);
1689
+ }
1690
+ }
1691
+ }
1692
+ emitError(error) {
1693
+ for (const handler of this.errorHandlers) {
1694
+ try {
1695
+ handler(error);
1696
+ } catch (e) {
1697
+ console.error("Error handler error:", e);
1698
+ }
1699
+ }
1700
+ }
1701
+ emitEvent(event) {
1702
+ for (const handler of this.eventHandlers) {
1703
+ try {
1704
+ handler(event);
1705
+ } catch (error) {
1706
+ console.error("Event handler error:", error);
1707
+ }
1708
+ }
1709
+ }
1710
+ handleMessage(data) {
1711
+ try {
1712
+ const message = JSON.parse(typeof data === "string" ? data : data.toString());
1713
+ if (message.type === "connected") {
1714
+ return;
1715
+ }
1716
+ if (message.type === "subscription_confirmed" || message.type === "subscription_error") {
1717
+ const confirmation = message;
1718
+ const key = this.getSubscriptionKey(confirmation);
1719
+ const pending = this.pendingSubscriptions.get(key);
1720
+ if (pending) {
1721
+ this.pendingSubscriptions.delete(key);
1722
+ if (confirmation.type === "subscription_error") {
1723
+ pending.reject(new Error(confirmation.error || "Subscription failed"));
1724
+ } else {
1725
+ pending.resolve(confirmation);
1726
+ }
1727
+ }
1728
+ return;
1729
+ }
1730
+ if (message.type === "event" && message.data) {
1731
+ const eventData = message.data;
1732
+ const event = {
1733
+ id: eventData.id,
1734
+ tenantId: eventData.tenant_id || eventData.tenantId,
1735
+ channelId: eventData.channel_id || eventData.channelId,
1736
+ canonicalType: eventData.canonical_type || eventData.canonicalType,
1737
+ eventType: eventData.event_type || eventData.eventType,
1738
+ direction: eventData.direction,
1739
+ payload: eventData.payload,
1740
+ enrichment: eventData.enrichment,
1741
+ timestamp: eventData.timestamp,
1742
+ processedAt: eventData.processed_at || eventData.processedAt
1743
+ };
1744
+ this.emitEvent(event);
1745
+ }
1746
+ } catch (error) {
1747
+ this.emitError(new Error(`Failed to parse message: ${error}`));
1748
+ }
1749
+ }
1750
+ async sendSubscription(command) {
1751
+ if (!this.ws || this.state !== "connected") {
1752
+ throw new Error("Not connected");
1753
+ }
1754
+ return new Promise((resolve, reject) => {
1755
+ const key = this.getSubscriptionKey({
1756
+ action: command.type,
1757
+ subscriptionType: command.subscriptionType
1758
+ });
1759
+ const timeout = setTimeout(() => {
1760
+ this.pendingSubscriptions.delete(key);
1761
+ reject(new Error("Subscription timeout"));
1762
+ }, 1e4);
1763
+ this.pendingSubscriptions.set(key, {
1764
+ resolve: (confirmation) => {
1765
+ clearTimeout(timeout);
1766
+ resolve(confirmation);
1767
+ },
1768
+ reject: (error) => {
1769
+ clearTimeout(timeout);
1770
+ reject(error);
1771
+ }
1772
+ });
1773
+ this.ws.send(JSON.stringify(command));
1774
+ });
1775
+ }
1776
+ getSubscriptionKey(confirmation) {
1777
+ return `${confirmation.action}:${confirmation.subscriptionType}`;
1778
+ }
1779
+ shouldReconnect() {
1780
+ if (this.config.maxReconnectAttempts === 0) {
1781
+ return true;
1782
+ }
1783
+ return this.reconnectAttempts < this.config.maxReconnectAttempts;
1784
+ }
1785
+ scheduleReconnect() {
1786
+ if (this.reconnectTimeout) return;
1787
+ this.setState("reconnecting");
1788
+ this.reconnectAttempts++;
1789
+ const delay = Math.min(
1790
+ this.config.reconnectInterval * Math.pow(2, this.reconnectAttempts - 1),
1791
+ MAX_RECONNECT_INTERVAL
1792
+ );
1793
+ this.reconnectTimeout = setTimeout(async () => {
1794
+ this.reconnectTimeout = null;
1795
+ try {
1796
+ await this.connect();
1797
+ } catch {
1798
+ }
1799
+ }, delay);
1800
+ }
1801
+ clearReconnectTimeout() {
1802
+ if (this.reconnectTimeout) {
1803
+ clearTimeout(this.reconnectTimeout);
1804
+ this.reconnectTimeout = null;
1805
+ }
1806
+ }
1807
+ async resubscribe() {
1808
+ try {
1809
+ if (this.activeSubscriptions.subscribedToAll) {
1810
+ await this.subscribeAll();
1811
+ }
1812
+ if (this.activeSubscriptions.channels.size > 0) {
1813
+ await this.subscribeChannels(Array.from(this.activeSubscriptions.channels));
1814
+ }
1815
+ if (this.activeSubscriptions.eventTypes.size > 0) {
1816
+ await this.subscribeEventTypes(Array.from(this.activeSubscriptions.eventTypes));
1817
+ }
1818
+ } catch (error) {
1819
+ this.emitError(new Error(`Failed to resubscribe: ${error}`));
1820
+ }
1821
+ }
1822
+ startHeartbeat() {
1823
+ this.stopHeartbeat();
1824
+ this.heartbeatInterval = setInterval(() => {
1825
+ if (this.ws && this.state === "connected") {
1826
+ if (typeof this.ws.ping === "function") {
1827
+ this.ws.ping();
1828
+ }
1829
+ }
1830
+ }, this.config.heartbeatInterval);
1831
+ }
1832
+ stopHeartbeat() {
1833
+ if (this.heartbeatInterval) {
1834
+ clearInterval(this.heartbeatInterval);
1835
+ this.heartbeatInterval = null;
1836
+ }
1837
+ }
1838
+ };
1839
+ function createRealtimeResource(tokenFetcher, config) {
1840
+ return new RealtimeResource(tokenFetcher, config);
1841
+ }
1842
+
1843
+ // src/client.ts
1844
+ var VeroAI = class _VeroAI {
1845
+ http;
1846
+ /** Manage communication channels (email, SMS, WhatsApp, etc.) */
1847
+ channels;
1848
+ /** Query activity events and analytics */
1849
+ events;
1850
+ /** Send messages through channels */
1851
+ messages;
1852
+ /** Manage webhook endpoints for real-time notifications */
1853
+ webhooks;
1854
+ /** Manage API keys for authentication */
1855
+ apiKeys;
1856
+ /** Manage email domains for sending */
1857
+ domains;
1858
+ /** Voice phone numbers and call management */
1859
+ voice;
1860
+ /** AI agent configurations */
1861
+ agents;
1862
+ /** Real-time event subscriptions via WebSocket */
1863
+ realtime;
1864
+ /**
1865
+ * Create a new VeroAI client instance
1866
+ *
1867
+ * @param config - Configuration options
1868
+ * @param config.apiKey - Your API key (required)
1869
+ * @param config.baseUrl - Custom API base URL (optional)
1870
+ * @param config.timeout - Request timeout in ms (default: 30000)
1871
+ * @param config.maxRetries - Max retry attempts (default: 3)
1872
+ * @param config.realtime - Realtime WebSocket configuration
1873
+ *
1874
+ * @example
1875
+ * ```typescript
1876
+ * // Basic usage
1877
+ * const veroai = new VeroAI({ apiKey: 'sk_live_...' });
1878
+ *
1879
+ * // With custom options
1880
+ * const veroai = new VeroAI({
1881
+ * apiKey: 'sk_test_...',
1882
+ * baseUrl: 'https://api.staging.veroai.dev',
1883
+ * timeout: 60000,
1884
+ * maxRetries: 5,
1885
+ * });
1886
+ * ```
1887
+ */
1888
+ constructor(config) {
1889
+ this.http = new HttpClient(config);
1890
+ this.channels = new ChannelsResource(this.http);
1891
+ this.events = new EventsResource(this.http);
1892
+ this.messages = new MessagesResource(this.http);
1893
+ this.webhooks = new WebhooksResource(this.http);
1894
+ this.apiKeys = new ApiKeysResource(this.http);
1895
+ this.domains = new DomainsResource(this.http);
1896
+ this.voice = new VoiceResource(this.http);
1897
+ this.agents = new AgentsResource(this.http);
1898
+ const tokenFetcher = async () => {
1899
+ const response = await this.http.post("/v1/realtime/auth", {});
1900
+ return response.token;
1901
+ };
1902
+ this.realtime = new RealtimeResource(tokenFetcher, config.realtime);
1903
+ }
1904
+ /**
1905
+ * Create a client from environment variables
1906
+ *
1907
+ * Looks for VEROAI_API_KEY environment variable
1908
+ *
1909
+ * @example
1910
+ * ```typescript
1911
+ * // Reads VEROAI_API_KEY from environment
1912
+ * const veroai = VeroAI.fromEnv();
1913
+ * ```
1914
+ */
1915
+ static fromEnv(overrides) {
1916
+ const apiKey = process.env.VEROAI_API_KEY;
1917
+ if (!apiKey) {
1918
+ throw new Error("VEROAI_API_KEY environment variable is not set");
1919
+ }
1920
+ return new _VeroAI({
1921
+ apiKey,
1922
+ baseUrl: process.env.VEROAI_BASE_URL,
1923
+ ...overrides
1924
+ });
1925
+ }
1926
+ };
1927
+
1928
+ exports.APIError = APIError;
1929
+ exports.AuthenticationError = AuthenticationError;
1930
+ exports.AuthorizationError = AuthorizationError;
1931
+ exports.NetworkError = NetworkError;
1932
+ exports.NotFoundError = NotFoundError;
1933
+ exports.RateLimitError = RateLimitError;
1934
+ exports.RealtimeResource = RealtimeResource;
1935
+ exports.ServerError = ServerError;
1936
+ exports.TimeoutError = TimeoutError;
1937
+ exports.ValidationError = ValidationError;
1938
+ exports.VeroAI = VeroAI;
1939
+ exports.VeroAIError = VeroAIError;
1940
+ exports.VoiceCallsResource = VoiceCallsResource;
1941
+ exports.VoiceNumbersResource = VoiceNumbersResource;
1942
+ exports.VoiceResource = VoiceResource;
1943
+ exports.createRealtimeResource = createRealtimeResource;
1944
+ exports.default = VeroAI;
1945
+ //# sourceMappingURL=index.cjs.map
1946
+ //# sourceMappingURL=index.cjs.map