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