@delegance/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.mjs ADDED
@@ -0,0 +1,1425 @@
1
+ // src/types/index.ts
2
+ import { z } from "zod";
3
+ var CompanySizeSchema = z.enum(["1", "2-10", "11-25", "26-50", "51-100", "100-499", "500+"]);
4
+ var CreateCompanySchema = z.object({
5
+ name: z.string().min(1).max(255),
6
+ legalName: z.string().max(255).optional(),
7
+ dba: z.string().max(255).optional(),
8
+ industry: z.string().min(1).max(100),
9
+ companySize: CompanySizeSchema,
10
+ yearEstablished: z.string().regex(/^\d{4}$/).optional(),
11
+ website: z.string().url().optional(),
12
+ fein: z.string().regex(/^\d{2}-\d{7}$/).optional(),
13
+ companyStructure: z.string().max(100).optional(),
14
+ description: z.string().max(2e3).optional(),
15
+ contactEmail: z.string().email(),
16
+ contactPhone: z.string().max(20).optional(),
17
+ address: z.object({
18
+ street: z.string().max(255),
19
+ suite: z.string().max(50).optional(),
20
+ city: z.string().max(100),
21
+ state: z.string().length(2),
22
+ zip: z.string().regex(/^\d{5}(-\d{4})?$/)
23
+ }).optional(),
24
+ externalId: z.string().max(255).optional(),
25
+ metadata: z.record(z.unknown()).optional()
26
+ });
27
+ var DocumentTypeSchema = z.enum([
28
+ "policy",
29
+ "loss_run",
30
+ "financial_statement",
31
+ "sov",
32
+ "application",
33
+ "certificate",
34
+ "endorsement",
35
+ "bor",
36
+ "other"
37
+ ]);
38
+ var DocumentStatusSchema = z.enum([
39
+ "pending",
40
+ "processing",
41
+ "completed",
42
+ "processed",
43
+ "error",
44
+ "failed"
45
+ ]);
46
+ var DeleganceError = class extends Error {
47
+ constructor(message, statusCode, traceId, details) {
48
+ super(message);
49
+ this.statusCode = statusCode;
50
+ this.traceId = traceId;
51
+ this.details = details;
52
+ this.name = "DeleganceError";
53
+ }
54
+ };
55
+ var AuthenticationError = class extends DeleganceError {
56
+ constructor(message, traceId) {
57
+ super(message, 401, traceId);
58
+ this.name = "AuthenticationError";
59
+ }
60
+ };
61
+ var ValidationError = class extends DeleganceError {
62
+ constructor(message, details, traceId) {
63
+ super(message, 400, traceId, details);
64
+ this.name = "ValidationError";
65
+ }
66
+ };
67
+ var NotFoundError = class extends DeleganceError {
68
+ constructor(message, traceId) {
69
+ super(message, 404, traceId);
70
+ this.name = "NotFoundError";
71
+ }
72
+ };
73
+ var RateLimitError = class extends DeleganceError {
74
+ constructor(message, retryAfter, traceId) {
75
+ super(message, 429, traceId);
76
+ this.retryAfter = retryAfter;
77
+ this.name = "RateLimitError";
78
+ }
79
+ };
80
+
81
+ // src/utils/http.ts
82
+ var SDK_VERSION = "0.1.0";
83
+ var HttpClient = class {
84
+ constructor(config) {
85
+ this.config = {
86
+ baseUrl: (config.baseUrl || "https://app.delegance.ai").replace(/\/$/, ""),
87
+ apiKey: config.apiKey,
88
+ timeout: config.timeout || 3e4,
89
+ retries: config.retries ?? 3,
90
+ headers: config.headers || {}
91
+ };
92
+ }
93
+ async request(options) {
94
+ const { method, path, body, headers = {}, timeout, isFormData } = options;
95
+ const url = `${this.config.baseUrl}${path}`;
96
+ const requestHeaders = {
97
+ "Authorization": `Bearer ${this.config.apiKey}`,
98
+ "User-Agent": `delegance-sdk/${SDK_VERSION}`,
99
+ ...this.config.headers,
100
+ ...headers
101
+ };
102
+ if (!isFormData) {
103
+ requestHeaders["Content-Type"] = "application/json";
104
+ }
105
+ return this.executeWithRetry(
106
+ () => ({
107
+ url,
108
+ init: {
109
+ method,
110
+ headers: requestHeaders,
111
+ body: body ? isFormData ? body : JSON.stringify(body) : void 0
112
+ }
113
+ }),
114
+ timeout || this.config.timeout
115
+ );
116
+ }
117
+ /**
118
+ * Upload a file with multipart form data.
119
+ * Retries on 5xx/network errors like request().
120
+ */
121
+ async uploadFile(path, file, fileName, additionalFields = {}) {
122
+ const url = `${this.config.baseUrl}${path}`;
123
+ const formData = new FormData();
124
+ if (Buffer.isBuffer(file)) {
125
+ const arrayBuffer = file.buffer.slice(file.byteOffset, file.byteOffset + file.byteLength);
126
+ formData.append("file", new Blob([arrayBuffer]), fileName);
127
+ } else {
128
+ formData.append("file", file, fileName);
129
+ }
130
+ formData.append("fileName", fileName);
131
+ for (const [key, value] of Object.entries(additionalFields)) {
132
+ formData.append(key, value);
133
+ }
134
+ const uploadHeaders = {
135
+ "Authorization": `Bearer ${this.config.apiKey}`,
136
+ "User-Agent": `delegance-sdk/${SDK_VERSION}`,
137
+ ...this.config.headers
138
+ // Don't set Content-Type for FormData — browser sets it with boundary
139
+ };
140
+ return this.executeWithRetry(
141
+ () => ({
142
+ url,
143
+ init: {
144
+ method: "POST",
145
+ headers: uploadHeaders,
146
+ body: formData
147
+ }
148
+ }),
149
+ this.config.timeout * 2
150
+ // Double timeout for uploads
151
+ );
152
+ }
153
+ /**
154
+ * Shared retry logic for both request() and uploadFile().
155
+ * Creates a fresh AbortController per attempt, clears timeout in finally,
156
+ * and excludes non-retryable errors (401, 400, 404, 429).
157
+ */
158
+ async executeWithRetry(buildRequest, timeoutMs) {
159
+ let lastError = null;
160
+ let attempts = 0;
161
+ while (attempts <= this.config.retries) {
162
+ const controller = new AbortController();
163
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
164
+ try {
165
+ const { url, init } = buildRequest();
166
+ const response = await fetch(url, { ...init, signal: controller.signal });
167
+ const data = await response.json().catch(() => ({}));
168
+ const traceId = data.traceId;
169
+ if (!response.ok) {
170
+ throw this.handleErrorResponse(response.status, data, traceId);
171
+ }
172
+ return data;
173
+ } catch (error) {
174
+ lastError = error;
175
+ if (error instanceof AuthenticationError || error instanceof ValidationError || error instanceof NotFoundError || error instanceof RateLimitError) {
176
+ throw error;
177
+ }
178
+ if (attempts < this.config.retries) {
179
+ attempts++;
180
+ await this.delay(Math.pow(2, attempts) * 1e3);
181
+ continue;
182
+ }
183
+ throw error;
184
+ } finally {
185
+ clearTimeout(timeoutId);
186
+ }
187
+ }
188
+ throw lastError || new DeleganceError("Request failed after retries", 500);
189
+ }
190
+ handleErrorResponse(status, data, traceId) {
191
+ const message = data.message || data.error || "Unknown error";
192
+ const details = data.details;
193
+ switch (status) {
194
+ case 401:
195
+ return new AuthenticationError(message, traceId);
196
+ case 400:
197
+ return new ValidationError(message, details, traceId);
198
+ case 404:
199
+ return new NotFoundError(message, traceId);
200
+ case 429:
201
+ return new RateLimitError(
202
+ message,
203
+ data.retryAfter,
204
+ traceId
205
+ );
206
+ default:
207
+ return new DeleganceError(message, status, traceId, details);
208
+ }
209
+ }
210
+ delay(ms) {
211
+ return new Promise((resolve) => setTimeout(resolve, ms));
212
+ }
213
+ };
214
+
215
+ // src/modules/companies.ts
216
+ var CompaniesModule = class {
217
+ constructor(http) {
218
+ this.http = http;
219
+ }
220
+ /**
221
+ * Create a new company
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * const company = await client.companies.create({
226
+ * name: 'ABC Construction',
227
+ * industry: 'construction',
228
+ * companySize: '11-25',
229
+ * contactEmail: 'contact@abc.com',
230
+ * fein: '12-3456789'
231
+ * });
232
+ * ```
233
+ */
234
+ async create(input) {
235
+ const parseResult = CreateCompanySchema.safeParse(input);
236
+ if (!parseResult.success) {
237
+ throw new ValidationError(
238
+ "Invalid company data",
239
+ parseResult.error.issues
240
+ );
241
+ }
242
+ const response = await this.http.request({
243
+ method: "POST",
244
+ path: "/api/v1/companies",
245
+ body: parseResult.data
246
+ });
247
+ return response.company;
248
+ }
249
+ /**
250
+ * List companies accessible to this API key
251
+ *
252
+ * @example
253
+ * ```typescript
254
+ * const companies = await client.companies.list();
255
+ *
256
+ * // Include companies created via this API key
257
+ * const allCompanies = await client.companies.list({ includeCreated: true });
258
+ * ```
259
+ */
260
+ async list(options = {}) {
261
+ const params = new URLSearchParams();
262
+ if (options.includeCreated) {
263
+ params.set("includeCreated", "true");
264
+ }
265
+ const query = params.toString();
266
+ const path = query ? `/api/v1/companies?${query}` : "/api/v1/companies";
267
+ const response = await this.http.request({
268
+ method: "GET",
269
+ path
270
+ });
271
+ return response.companies;
272
+ }
273
+ /**
274
+ * Get a company by ID
275
+ *
276
+ * @example
277
+ * ```typescript
278
+ * const company = await client.companies.get('uuid-here');
279
+ * ```
280
+ */
281
+ async get(companyId) {
282
+ const response = await this.http.request({
283
+ method: "GET",
284
+ path: `/api/v1/companies/${companyId}`
285
+ });
286
+ return response.company;
287
+ }
288
+ /**
289
+ * Create a company if it doesn't exist (using externalId for deduplication)
290
+ *
291
+ * @example
292
+ * ```typescript
293
+ * const company = await client.companies.upsert({
294
+ * name: 'ABC Construction',
295
+ * industry: 'construction',
296
+ * companySize: '11-25',
297
+ * contactEmail: 'contact@abc.com',
298
+ * externalId: 'ams-12345' // Will dedupe on this
299
+ * });
300
+ * ```
301
+ */
302
+ async upsert(input) {
303
+ const parseResult = CreateCompanySchema.safeParse(input);
304
+ if (!parseResult.success) {
305
+ throw new ValidationError(
306
+ "Invalid company data",
307
+ parseResult.error.issues
308
+ );
309
+ }
310
+ const response = await this.http.request({
311
+ method: "POST",
312
+ path: "/api/v1/companies",
313
+ body: parseResult.data
314
+ });
315
+ return {
316
+ company: response.company,
317
+ isExisting: response.isExisting
318
+ };
319
+ }
320
+ };
321
+
322
+ // src/modules/documents.ts
323
+ var DocumentsModule = class {
324
+ constructor(http) {
325
+ this.http = http;
326
+ }
327
+ /**
328
+ * Upload a document for processing
329
+ *
330
+ * @example
331
+ * ```typescript
332
+ * import fs from 'fs';
333
+ *
334
+ * const doc = await client.documents.upload({
335
+ * companyId: 'company-uuid',
336
+ * file: fs.readFileSync('./policy.pdf'),
337
+ * fileName: 'GL-2025.pdf',
338
+ * documentType: 'policy'
339
+ * });
340
+ *
341
+ * console.log(`Document ${doc.id} uploaded, status: ${doc.status}`);
342
+ * ```
343
+ */
344
+ async upload(input) {
345
+ if (!input.companyId) {
346
+ throw new ValidationError("companyId is required");
347
+ }
348
+ if (!input.file) {
349
+ throw new ValidationError("file is required");
350
+ }
351
+ if (!input.fileName) {
352
+ throw new ValidationError("fileName is required");
353
+ }
354
+ let fileData;
355
+ if (typeof input.file === "string") {
356
+ fileData = Buffer.from(input.file, "base64");
357
+ } else {
358
+ fileData = input.file;
359
+ }
360
+ const additionalFields = {
361
+ companyId: input.companyId
362
+ };
363
+ if (input.documentType) {
364
+ additionalFields.documentType = input.documentType;
365
+ }
366
+ if (input.externalId) {
367
+ additionalFields.externalId = input.externalId;
368
+ }
369
+ if (input.metadata) {
370
+ additionalFields.metadata = JSON.stringify(input.metadata);
371
+ }
372
+ const response = await this.http.uploadFile(
373
+ "/api/v1/documents",
374
+ fileData,
375
+ input.fileName,
376
+ additionalFields
377
+ );
378
+ return response.document;
379
+ }
380
+ /**
381
+ * Upload multiple documents in batch
382
+ *
383
+ * @example
384
+ * ```typescript
385
+ * const docs = await client.documents.uploadBatch([
386
+ * { companyId, file: buffer1, fileName: 'policy1.pdf' },
387
+ * { companyId, file: buffer2, fileName: 'policy2.pdf' }
388
+ * ]);
389
+ * ```
390
+ */
391
+ async uploadBatch(inputs, options = {}) {
392
+ const concurrency = options.concurrency || 3;
393
+ const documents = [];
394
+ const errors = [];
395
+ for (let i = 0; i < inputs.length; i += concurrency) {
396
+ const batch = inputs.slice(i, i + concurrency);
397
+ const results = await Promise.allSettled(
398
+ batch.map((input) => this.upload(input))
399
+ );
400
+ for (let j = 0; j < results.length; j++) {
401
+ const result = results[j];
402
+ if (result.status === "fulfilled") {
403
+ documents.push(result.value);
404
+ } else {
405
+ errors.push({ input: batch[j], error: result.reason });
406
+ }
407
+ }
408
+ }
409
+ return { documents, errors };
410
+ }
411
+ /**
412
+ * Get document details and extraction status
413
+ *
414
+ * @example
415
+ * ```typescript
416
+ * const doc = await client.documents.get('doc-uuid');
417
+ * console.log(`Status: ${doc.status}`);
418
+ * if (doc.extraction) {
419
+ * console.log(`Found ${doc.extraction.policies.length} policies`);
420
+ * }
421
+ * ```
422
+ */
423
+ async get(documentId) {
424
+ const response = await this.http.request({
425
+ method: "GET",
426
+ path: `/api/v1/documents/${documentId}`
427
+ });
428
+ return {
429
+ ...response.document,
430
+ extraction: response.extraction,
431
+ processing: response.processing,
432
+ error: response.error
433
+ };
434
+ }
435
+ /**
436
+ * List documents with optional filters
437
+ *
438
+ * @example
439
+ * ```typescript
440
+ * // List all documents
441
+ * const docs = await client.documents.list();
442
+ *
443
+ * // Filter by type and status
444
+ * const policies = await client.documents.list({
445
+ * documentType: 'policy',
446
+ * status: 'completed'
447
+ * });
448
+ *
449
+ * // Paginate
450
+ * const page2 = await client.documents.list({ offset: 50, limit: 50 });
451
+ * ```
452
+ */
453
+ async list(options = {}) {
454
+ const params = new URLSearchParams();
455
+ if (options.companyId) params.set("companyId", options.companyId);
456
+ if (options.documentType) params.set("documentType", options.documentType);
457
+ if (options.status) params.set("status", options.status);
458
+ if (options.externalId) params.set("externalId", options.externalId);
459
+ if (options.limit) params.set("limit", String(options.limit));
460
+ if (options.offset) params.set("offset", String(options.offset));
461
+ const query = params.toString();
462
+ const path = query ? `/api/v1/documents?${query}` : "/api/v1/documents";
463
+ const response = await this.http.request({
464
+ method: "GET",
465
+ path
466
+ });
467
+ return {
468
+ documents: response.documents,
469
+ pagination: response.pagination
470
+ };
471
+ }
472
+ /**
473
+ * Wait for document extraction to complete
474
+ *
475
+ * @example
476
+ * ```typescript
477
+ * const doc = await client.documents.upload({ ... });
478
+ *
479
+ * // Wait for processing to complete
480
+ * const result = await client.documents.waitForExtraction(doc.id, {
481
+ * timeoutMs: 60000,
482
+ * onStatusChange: (status) => console.log(`Status: ${status}`)
483
+ * });
484
+ *
485
+ * if (result.extraction) {
486
+ * console.log('Extraction complete:', result.extraction.policies);
487
+ * }
488
+ * ```
489
+ */
490
+ async waitForExtraction(documentId, options = {}) {
491
+ const {
492
+ timeoutMs = 12e4,
493
+ pollIntervalMs = 2e3,
494
+ onStatusChange
495
+ } = options;
496
+ const startTime = Date.now();
497
+ let lastStatus = null;
498
+ while (Date.now() - startTime < timeoutMs) {
499
+ try {
500
+ const doc = await this.get(documentId);
501
+ if (onStatusChange && doc.status !== lastStatus) {
502
+ onStatusChange(doc.status);
503
+ lastStatus = doc.status;
504
+ }
505
+ if (doc.status === "completed" || doc.status === "processed") {
506
+ return doc;
507
+ }
508
+ if (doc.status === "error" || doc.status === "failed") {
509
+ return doc;
510
+ }
511
+ } catch (error) {
512
+ if (error instanceof NotFoundError || error instanceof AuthenticationError || error instanceof RateLimitError || error instanceof ValidationError) {
513
+ throw error;
514
+ }
515
+ }
516
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
517
+ }
518
+ throw new DeleganceError(
519
+ `Document ${documentId} extraction did not complete within ${timeoutMs}ms (last status: ${lastStatus || "unknown"})`,
520
+ 408
521
+ );
522
+ }
523
+ /**
524
+ * Check if a document with the given external ID already exists
525
+ *
526
+ * @example
527
+ * ```typescript
528
+ * const existing = await client.documents.findByExternalId('ams-doc-123');
529
+ * if (existing) {
530
+ * console.log('Document already uploaded:', existing.id);
531
+ * }
532
+ * ```
533
+ */
534
+ async findByExternalId(externalId, companyId) {
535
+ const params = new URLSearchParams();
536
+ params.set("externalId", externalId);
537
+ params.set("limit", "1");
538
+ if (companyId) params.set("companyId", companyId);
539
+ const response = await this.http.request({
540
+ method: "GET",
541
+ path: `/api/v1/documents?${params.toString()}`
542
+ });
543
+ return response.documents[0] || null;
544
+ }
545
+ /**
546
+ * Archive a document (soft delete)
547
+ *
548
+ * This does NOT permanently delete the document - archived documents
549
+ * are excluded from list queries but remain for audit purposes.
550
+ *
551
+ * @example
552
+ * ```typescript
553
+ * await client.documents.archive('doc-uuid');
554
+ * console.log('Document archived');
555
+ * ```
556
+ */
557
+ async archive(documentId) {
558
+ const response = await this.http.request({
559
+ method: "PATCH",
560
+ path: `/api/v1/documents/${documentId}`,
561
+ body: { action: "archive" }
562
+ });
563
+ return { success: response.success, message: response.message };
564
+ }
565
+ /**
566
+ * Unarchive a previously archived document
567
+ *
568
+ * @example
569
+ * ```typescript
570
+ * await client.documents.unarchive('doc-uuid');
571
+ * console.log('Document restored');
572
+ * ```
573
+ */
574
+ async unarchive(documentId) {
575
+ const response = await this.http.request({
576
+ method: "PATCH",
577
+ path: `/api/v1/documents/${documentId}`,
578
+ body: { action: "unarchive" }
579
+ });
580
+ return { success: response.success, message: response.message, status: response.status };
581
+ }
582
+ /**
583
+ * Trigger re-extraction of a document
584
+ *
585
+ * Useful when:
586
+ * - Document extraction failed
587
+ * - You want to try extraction with updated extractors
588
+ * - Document was partially processed
589
+ *
590
+ * Rate limited to 3 reprocesses per document per day.
591
+ *
592
+ * @example
593
+ * ```typescript
594
+ * const result = await client.documents.reprocess('doc-uuid');
595
+ * console.log(`Reprocessing initiated. ${result.reprocessesRemaining} retries remaining today.`);
596
+ *
597
+ * // Then wait for extraction
598
+ * const doc = await client.documents.waitForExtraction('doc-uuid');
599
+ * ```
600
+ */
601
+ async reprocess(documentId) {
602
+ const response = await this.http.request({
603
+ method: "POST",
604
+ path: `/api/v1/documents/${documentId}/reprocess`
605
+ });
606
+ return {
607
+ success: response.success,
608
+ message: response.message,
609
+ status: response.status,
610
+ reprocessesRemaining: response.reprocessesRemaining
611
+ };
612
+ }
613
+ };
614
+
615
+ // src/modules/chat.ts
616
+ var ChatModule = class {
617
+ constructor(http) {
618
+ this.http = http;
619
+ }
620
+ /**
621
+ * Send a message to the Orin insurance assistant
622
+ *
623
+ * @example
624
+ * ```typescript
625
+ * const response = await client.chat.ask('What is my GL coverage limit?');
626
+ * console.log(response.response);
627
+ *
628
+ * // Continue the conversation
629
+ * const followUp = await client.chat.ask('And when does it expire?', {
630
+ * conversationId: response.conversationId
631
+ * });
632
+ * ```
633
+ */
634
+ async ask(message, options = {}) {
635
+ const response = await this.http.request({
636
+ method: "POST",
637
+ path: "/api/v1/chat",
638
+ body: {
639
+ message,
640
+ conversationId: options.conversationId,
641
+ context: options.context
642
+ }
643
+ });
644
+ return response;
645
+ }
646
+ /**
647
+ * Start a new conversation and send the first message
648
+ *
649
+ * @example
650
+ * ```typescript
651
+ * const conversation = await client.chat.startConversation('Tell me about my policies');
652
+ * console.log('Conversation ID:', conversation.conversationId);
653
+ * ```
654
+ */
655
+ async startConversation(message) {
656
+ return this.ask(message, {
657
+ conversationId: crypto.randomUUID()
658
+ });
659
+ }
660
+ };
661
+
662
+ // src/modules/quotes.ts
663
+ var QuotesModule = class {
664
+ constructor(http) {
665
+ this.http = http;
666
+ }
667
+ /**
668
+ * List available carriers for quoting
669
+ *
670
+ * @example
671
+ * ```typescript
672
+ * const { carriers } = await client.quotes.listCarriers();
673
+ * for (const carrier of carriers) {
674
+ * console.log(`${carrier.name} - avg ${carrier.averageQuoteTimeSeconds}s`);
675
+ * }
676
+ * ```
677
+ */
678
+ async listCarriers() {
679
+ return this.http.request({
680
+ method: "GET",
681
+ path: "/api/v1/quotes/carriers"
682
+ });
683
+ }
684
+ /**
685
+ * Submit a quote request to one or more carriers
686
+ *
687
+ * @example
688
+ * ```typescript
689
+ * // Get available carriers
690
+ * const { carriers } = await client.quotes.listCarriers();
691
+ *
692
+ * // Submit to first 3 carriers
693
+ * const result = await client.quotes.submit({
694
+ * carriers: carriers.slice(0, 3).map(c => c.id),
695
+ * priority: 'high'
696
+ * });
697
+ *
698
+ * console.log(`Submitted ${result.queueIds.length} quote requests`);
699
+ * ```
700
+ */
701
+ async submit(request) {
702
+ return this.http.request({
703
+ method: "POST",
704
+ path: "/api/v1/quotes",
705
+ body: request
706
+ });
707
+ }
708
+ /**
709
+ * List quote requests for the company
710
+ *
711
+ * @example
712
+ * ```typescript
713
+ * // List all quotes
714
+ * const { quotes } = await client.quotes.list();
715
+ *
716
+ * // List only pending quotes
717
+ * const { quotes: pending } = await client.quotes.list({ status: 'pending' });
718
+ * ```
719
+ */
720
+ async list(options = {}) {
721
+ const params = new URLSearchParams();
722
+ if (options.status) params.set("status", options.status);
723
+ if (options.limit) params.set("limit", String(options.limit));
724
+ const query = params.toString();
725
+ const path = query ? `/api/v1/quotes?${query}` : "/api/v1/quotes";
726
+ return this.http.request({
727
+ method: "GET",
728
+ path
729
+ });
730
+ }
731
+ /**
732
+ * Get a single quote by ID with full details
733
+ *
734
+ * @example
735
+ * ```typescript
736
+ * const { quote, actions } = await client.quotes.get('quote-uuid');
737
+ * console.log(`Status: ${quote.status}`);
738
+ * if (actions.canCancel) {
739
+ * console.log('This quote can be cancelled');
740
+ * }
741
+ * ```
742
+ */
743
+ async get(quoteId) {
744
+ const response = await this.http.request({
745
+ method: "GET",
746
+ path: `/api/v1/quotes/${quoteId}`
747
+ });
748
+ return {
749
+ quote: response.quote,
750
+ canCancel: response.actions.canCancel
751
+ };
752
+ }
753
+ /**
754
+ * Cancel a pending quote
755
+ *
756
+ * Only quotes in 'pending' status can be cancelled.
757
+ * Once a quote starts processing, it cannot be stopped.
758
+ *
759
+ * @example
760
+ * ```typescript
761
+ * try {
762
+ * await client.quotes.cancel('quote-uuid');
763
+ * console.log('Quote cancelled');
764
+ * } catch (error) {
765
+ * console.log('Cannot cancel:', error.message);
766
+ * }
767
+ * ```
768
+ */
769
+ async cancel(quoteId) {
770
+ const response = await this.http.request({
771
+ method: "DELETE",
772
+ path: `/api/v1/quotes/${quoteId}`
773
+ });
774
+ return { success: response.success, message: response.message };
775
+ }
776
+ /**
777
+ * Wait for a quote to complete
778
+ *
779
+ * @example
780
+ * ```typescript
781
+ * const result = await client.quotes.submit({ carriers: ['carrier-1'] });
782
+ * const quote = await client.quotes.waitForCompletion(result.queueIds[0]);
783
+ * console.log('Quote status:', quote.status);
784
+ * ```
785
+ */
786
+ async waitForCompletion(quoteId, options = {}) {
787
+ const { timeoutMs = 3e5, pollIntervalMs = 5e3 } = options;
788
+ const startTime = Date.now();
789
+ while (Date.now() - startTime < timeoutMs) {
790
+ try {
791
+ const { quote } = await this.get(quoteId);
792
+ if (["completed", "failed", "cancelled"].includes(quote.status)) {
793
+ return quote;
794
+ }
795
+ } catch (error) {
796
+ if (error instanceof NotFoundError || error instanceof AuthenticationError || error instanceof RateLimitError || error instanceof ValidationError) {
797
+ throw error;
798
+ }
799
+ }
800
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
801
+ }
802
+ throw new DeleganceError(`Quote ${quoteId} did not complete within ${timeoutMs}ms`, 408);
803
+ }
804
+ };
805
+
806
+ // src/modules/policies.ts
807
+ var PoliciesModule = class {
808
+ constructor(http) {
809
+ this.http = http;
810
+ }
811
+ /**
812
+ * List policies for the company
813
+ *
814
+ * @example
815
+ * ```typescript
816
+ * // List all active policies
817
+ * const { policies } = await client.policies.list({ status: 'active' });
818
+ *
819
+ * // List policies expiring in 30 days
820
+ * const { policies: expiring } = await client.policies.list({ expiringDays: 30 });
821
+ * ```
822
+ */
823
+ async list(options = {}) {
824
+ const params = new URLSearchParams();
825
+ if (options.status && options.status !== "all") params.set("status", options.status);
826
+ if (options.expiringDays) params.set("expiring", String(options.expiringDays));
827
+ if (options.policyType) params.set("type", options.policyType);
828
+ if (options.limit) params.set("limit", String(options.limit));
829
+ const query = params.toString();
830
+ const path = query ? `/api/v1/policies?${query}` : "/api/v1/policies";
831
+ return this.http.request({
832
+ method: "GET",
833
+ path
834
+ });
835
+ }
836
+ /**
837
+ * Get policies expiring soon
838
+ *
839
+ * @param days - Number of days to look ahead (default: 30)
840
+ */
841
+ async getExpiring(days = 30) {
842
+ return this.list({ expiringDays: days, status: "active" });
843
+ }
844
+ /**
845
+ * Get a single policy by ID with full details
846
+ *
847
+ * @example
848
+ * ```typescript
849
+ * const { policy, coverages } = await client.policies.get('policy-uuid');
850
+ * console.log(`${policy.carrier} - ${policy.policyType}`);
851
+ * console.log(`Coverages: ${coverages.length}`);
852
+ * ```
853
+ */
854
+ async get(policyId) {
855
+ try {
856
+ const response = await this.http.request({
857
+ method: "GET",
858
+ path: `/api/v1/policies/${policyId}`
859
+ });
860
+ return {
861
+ policy: response.policy,
862
+ coverages: response.coverages || []
863
+ };
864
+ } catch (error) {
865
+ if (error instanceof NotFoundError) {
866
+ return null;
867
+ }
868
+ throw error;
869
+ }
870
+ }
871
+ };
872
+
873
+ // src/modules/coi.ts
874
+ var COIModule = class {
875
+ constructor(http) {
876
+ this.http = http;
877
+ }
878
+ /**
879
+ * Generate a Certificate of Insurance
880
+ *
881
+ * @example
882
+ * ```typescript
883
+ * const { policies } = await client.policies.list({ status: 'active' });
884
+ *
885
+ * const result = await client.coi.generate({
886
+ * policyIds: policies.map(p => p.id),
887
+ * certificateHolder: {
888
+ * name: 'ABC Property Management',
889
+ * address: '123 Main St',
890
+ * city: 'New York',
891
+ * state: 'NY',
892
+ * zip: '10001'
893
+ * },
894
+ * certificateType: 'additional_insured'
895
+ * });
896
+ *
897
+ * console.log('Download URL:', result.downloadUrl);
898
+ * ```
899
+ */
900
+ async generate(request) {
901
+ return this.http.request({
902
+ method: "POST",
903
+ path: "/api/v1/coi",
904
+ body: request
905
+ });
906
+ }
907
+ /**
908
+ * List generated COIs
909
+ *
910
+ * @param limit - Maximum results (default: 50)
911
+ */
912
+ async list(limit = 50) {
913
+ return this.http.request({
914
+ method: "GET",
915
+ path: `/api/v1/coi?limit=${limit}`
916
+ });
917
+ }
918
+ };
919
+
920
+ // src/modules/sov.ts
921
+ var SOVModule = class {
922
+ constructor(http) {
923
+ this.http = http;
924
+ }
925
+ /**
926
+ * Upload a Schedule of Values file
927
+ *
928
+ * @example
929
+ * ```typescript
930
+ * import fs from 'fs';
931
+ *
932
+ * const result = await client.sov.upload({
933
+ * file: fs.readFileSync('./property-schedule.xlsx'),
934
+ * fileName: 'property-schedule.xlsx',
935
+ * lineOfBusiness: 'property',
936
+ * effectiveDate: '2024-01-01'
937
+ * });
938
+ *
939
+ * console.log('SOV ID:', result.sovId);
940
+ * ```
941
+ */
942
+ async upload(request) {
943
+ let fileData;
944
+ if (request.file instanceof ArrayBuffer) {
945
+ fileData = new Blob([new Uint8Array(request.file)]);
946
+ } else {
947
+ fileData = request.file;
948
+ }
949
+ const additionalFields = {};
950
+ if (request.lineOfBusiness) additionalFields.lineOfBusiness = request.lineOfBusiness;
951
+ if (request.effectiveDate) additionalFields.effectiveDate = request.effectiveDate;
952
+ if (request.expirationDate) additionalFields.expirationDate = request.expirationDate;
953
+ return this.http.uploadFile(
954
+ "/api/v1/sov",
955
+ fileData,
956
+ request.fileName,
957
+ additionalFields
958
+ );
959
+ }
960
+ /**
961
+ * List SOVs for the company
962
+ */
963
+ async list(options = {}) {
964
+ const params = new URLSearchParams();
965
+ if (options.status) params.set("status", options.status);
966
+ if (options.limit) params.set("limit", String(options.limit));
967
+ const query = params.toString();
968
+ const path = query ? `/api/v1/sov?${query}` : "/api/v1/sov";
969
+ return this.http.request({
970
+ method: "GET",
971
+ path
972
+ });
973
+ }
974
+ /**
975
+ * Get a single SOV by ID with full details and locations
976
+ *
977
+ * @example
978
+ * ```typescript
979
+ * const { sov, locations } = await client.sov.get('sov-uuid');
980
+ * console.log(`${sov.totalLocations} locations, TIV: $${sov.totalTIV}`);
981
+ *
982
+ * // Access individual locations
983
+ * for (const loc of locations.items) {
984
+ * console.log(`${loc.address.city}, ${loc.address.state}: $${loc.values.total}`);
985
+ * }
986
+ * ```
987
+ */
988
+ async get(sovId, options = {}) {
989
+ const params = new URLSearchParams();
990
+ if (options.includeLocations !== void 0) {
991
+ params.set("includeLocations", String(options.includeLocations));
992
+ }
993
+ if (options.locationLimit) params.set("locationLimit", String(options.locationLimit));
994
+ if (options.locationOffset) params.set("locationOffset", String(options.locationOffset));
995
+ const query = params.toString();
996
+ const path = query ? `/api/v1/sov/${sovId}?${query}` : `/api/v1/sov/${sovId}`;
997
+ return this.http.request({
998
+ method: "GET",
999
+ path
1000
+ });
1001
+ }
1002
+ /**
1003
+ * Wait for SOV parsing to complete
1004
+ */
1005
+ async waitForParsing(sovId, options = {}) {
1006
+ const { timeoutMs = 12e4, pollIntervalMs = 3e3 } = options;
1007
+ const startTime = Date.now();
1008
+ while (Date.now() - startTime < timeoutMs) {
1009
+ try {
1010
+ const { sov } = await this.get(sovId, { includeLocations: false });
1011
+ if (["parsed", "validated", "submitted", "error"].includes(sov.status)) {
1012
+ return sov;
1013
+ }
1014
+ } catch (error) {
1015
+ if (error instanceof NotFoundError || error instanceof AuthenticationError || error instanceof RateLimitError || error instanceof ValidationError) {
1016
+ throw error;
1017
+ }
1018
+ }
1019
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
1020
+ }
1021
+ throw new DeleganceError(`SOV ${sovId} did not complete parsing within ${timeoutMs}ms`, 408);
1022
+ }
1023
+ };
1024
+
1025
+ // src/modules/api-keys.ts
1026
+ var ApiKeysModule = class {
1027
+ constructor(http) {
1028
+ this.http = http;
1029
+ }
1030
+ /**
1031
+ * Create a new API key.
1032
+ *
1033
+ * The returned `key` value (the full secret) is shown **only once**.
1034
+ * Store it securely — it cannot be retrieved again.
1035
+ *
1036
+ * @example
1037
+ * ```typescript
1038
+ * const created = await client.apiKeys.create({
1039
+ * name: 'My Integration Key',
1040
+ * scopes: ['read', 'write'],
1041
+ * expiresInDays: 365,
1042
+ * });
1043
+ * console.log('Save this key now:', created.key);
1044
+ * ```
1045
+ */
1046
+ async create(input, options) {
1047
+ if (!input.name || !input.name.trim()) {
1048
+ throw new ValidationError("API key name is required and cannot be blank");
1049
+ }
1050
+ const body = {
1051
+ name: input.name,
1052
+ scopes: input.scopes
1053
+ };
1054
+ if (input.expiresInDays !== void 0) {
1055
+ body.expiresInDays = input.expiresInDays;
1056
+ }
1057
+ const requestOptions = {
1058
+ method: "POST",
1059
+ path: "/api/v1/api-keys",
1060
+ body
1061
+ };
1062
+ if (options?.idempotencyKey) {
1063
+ requestOptions.headers = { "Idempotency-Key": options.idempotencyKey };
1064
+ }
1065
+ const response = await this.http.request(requestOptions);
1066
+ return response.data;
1067
+ }
1068
+ /**
1069
+ * List API keys for the current workspace.
1070
+ *
1071
+ * @example
1072
+ * ```typescript
1073
+ * const { data, pagination } = await client.apiKeys.list({ limit: 20 });
1074
+ * if (pagination.hasMore) {
1075
+ * const next = await client.apiKeys.list({ cursor: pagination.nextCursor });
1076
+ * }
1077
+ * ```
1078
+ */
1079
+ async list(options = {}) {
1080
+ const params = new URLSearchParams();
1081
+ if (options.limit !== void 0) {
1082
+ params.set("limit", String(options.limit));
1083
+ }
1084
+ if (options.cursor !== void 0) {
1085
+ params.set("cursor", options.cursor);
1086
+ }
1087
+ const query = params.toString();
1088
+ const path = query ? `/api/v1/api-keys?${query}` : "/api/v1/api-keys";
1089
+ const response = await this.http.request({
1090
+ method: "GET",
1091
+ path
1092
+ });
1093
+ return {
1094
+ data: response.data,
1095
+ pagination: response.pagination
1096
+ };
1097
+ }
1098
+ /**
1099
+ * Revoke an API key immediately.
1100
+ *
1101
+ * @example
1102
+ * ```typescript
1103
+ * await client.apiKeys.revoke('key-id-here');
1104
+ * ```
1105
+ */
1106
+ async revoke(keyId) {
1107
+ await this.http.request({
1108
+ method: "DELETE",
1109
+ path: `/api/v1/api-keys/${keyId}`
1110
+ });
1111
+ }
1112
+ /**
1113
+ * Rotate an API key.
1114
+ *
1115
+ * Issues a new key while keeping the old key valid for `gracePeriodHours`
1116
+ * so you have time to update your integrations.
1117
+ *
1118
+ * @example
1119
+ * ```typescript
1120
+ * const { newKey, oldKeyValidUntil } = await client.apiKeys.rotate(
1121
+ * 'key-id-here',
1122
+ * { gracePeriodHours: 24 },
1123
+ * { idempotencyKey: 'my-rotation-id' }
1124
+ * );
1125
+ * console.log('New key (save now):', newKey.key);
1126
+ * console.log('Old key expires:', oldKeyValidUntil);
1127
+ * ```
1128
+ */
1129
+ async rotate(keyId, options, idempotency) {
1130
+ const requestOptions = {
1131
+ method: "POST",
1132
+ path: `/api/v1/api-keys/${keyId}/rotate`,
1133
+ body: { gracePeriodHours: options.gracePeriodHours }
1134
+ };
1135
+ if (idempotency?.idempotencyKey) {
1136
+ requestOptions.headers = { "Idempotency-Key": idempotency.idempotencyKey };
1137
+ }
1138
+ const response = await this.http.request(requestOptions);
1139
+ return response.data;
1140
+ }
1141
+ };
1142
+
1143
+ // src/modules/usage.ts
1144
+ var UsageModule = class {
1145
+ constructor(http) {
1146
+ this.http = http;
1147
+ }
1148
+ /**
1149
+ * Get a billing-period summary across all meters.
1150
+ *
1151
+ * @example
1152
+ * ```typescript
1153
+ * const summary = await client.usage.summary();
1154
+ * console.log(`Plan: ${summary.plan}, overage: $${summary.totalOverageCents / 100}`);
1155
+ * ```
1156
+ */
1157
+ async summary() {
1158
+ const response = await this.http.request({
1159
+ method: "GET",
1160
+ path: "/api/v1/usage/summary"
1161
+ });
1162
+ return response.data;
1163
+ }
1164
+ /**
1165
+ * Get daily usage data for a date range.
1166
+ *
1167
+ * @example
1168
+ * ```typescript
1169
+ * const { data } = await client.usage.daily({
1170
+ * from: '2026-04-01',
1171
+ * to: '2026-04-30',
1172
+ * meter: 'api_requests',
1173
+ * });
1174
+ * const total = data.reduce((sum, row) => sum + row.quantity, 0);
1175
+ * ```
1176
+ */
1177
+ async daily(options) {
1178
+ if (!options.from) {
1179
+ throw new ValidationError('daily() requires a non-empty "from" date');
1180
+ }
1181
+ if (!options.to) {
1182
+ throw new ValidationError('daily() requires a non-empty "to" date');
1183
+ }
1184
+ const params = new URLSearchParams();
1185
+ params.set("from", options.from);
1186
+ params.set("to", options.to);
1187
+ if (options.meter !== void 0) {
1188
+ params.set("meter", options.meter);
1189
+ }
1190
+ if (options.groupBy !== void 0) {
1191
+ params.set("groupBy", options.groupBy);
1192
+ }
1193
+ const response = await this.http.request({
1194
+ method: "GET",
1195
+ path: `/api/v1/usage/daily?${params.toString()}`
1196
+ });
1197
+ return { data: response.data };
1198
+ }
1199
+ /**
1200
+ * Get the current rate-limit status for this API key.
1201
+ *
1202
+ * @example
1203
+ * ```typescript
1204
+ * const limits = await client.usage.rateLimits();
1205
+ * console.log(`${limits.remaining}/${limits.requestsPerMinute} requests remaining`);
1206
+ * ```
1207
+ */
1208
+ async rateLimits() {
1209
+ const response = await this.http.request({
1210
+ method: "GET",
1211
+ path: "/api/v1/usage/rate-limits"
1212
+ });
1213
+ return response.data;
1214
+ }
1215
+ };
1216
+
1217
+ // src/modules/knowledge.ts
1218
+ var KnowledgeModule = class {
1219
+ constructor(http) {
1220
+ this.http = http;
1221
+ }
1222
+ /**
1223
+ * Search notecards and document chunks using semantic search.
1224
+ *
1225
+ * Uses POST because the query body can be complex (filters, types, etc.).
1226
+ *
1227
+ * @example
1228
+ * ```typescript
1229
+ * const { data, pagination } = await client.knowledge.search({
1230
+ * query: 'general liability occurrence limit',
1231
+ * types: ['notecard'],
1232
+ * limit: 10,
1233
+ * });
1234
+ * console.log(data[0].title, data[0].score);
1235
+ * ```
1236
+ */
1237
+ async search(input) {
1238
+ if (!input.query || !input.query.trim()) {
1239
+ throw new ValidationError("search query must be a non-empty string");
1240
+ }
1241
+ const body = { query: input.query };
1242
+ if (input.types !== void 0) body.types = input.types;
1243
+ if (input.limit !== void 0) body.limit = input.limit;
1244
+ const response = await this.http.request({
1245
+ method: "POST",
1246
+ path: "/api/v1/knowledge/search",
1247
+ body
1248
+ });
1249
+ return { data: response.data, pagination: response.pagination };
1250
+ }
1251
+ /**
1252
+ * List notecards, optionally filtered by template type.
1253
+ *
1254
+ * @example
1255
+ * ```typescript
1256
+ * const { data, pagination } = await client.knowledge.notecards({
1257
+ * type: 'policy_summary',
1258
+ * limit: 50,
1259
+ * });
1260
+ * if (pagination.hasMore) {
1261
+ * const next = await client.knowledge.notecards({ cursor: pagination.nextCursor! });
1262
+ * }
1263
+ * ```
1264
+ */
1265
+ async notecards(options = {}) {
1266
+ const params = new URLSearchParams();
1267
+ if (options.type) params.set("type", options.type);
1268
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
1269
+ if (options.cursor) params.set("cursor", options.cursor);
1270
+ const query = params.toString();
1271
+ const path = query ? `/api/v1/knowledge/notecards?${query}` : "/api/v1/knowledge/notecards";
1272
+ const response = await this.http.request({
1273
+ method: "GET",
1274
+ path
1275
+ });
1276
+ return { data: response.data, pagination: response.pagination };
1277
+ }
1278
+ /**
1279
+ * Retrieve structured facts extracted from a document.
1280
+ *
1281
+ * @throws {NotFoundError} when the document does not exist
1282
+ *
1283
+ * @example
1284
+ * ```typescript
1285
+ * const facts = await client.knowledge.documentFacts('doc-uuid');
1286
+ * console.log(facts.carriers); // ['Hartford', 'Chubb']
1287
+ * console.log(facts.policies[0].policyType); // 'GL'
1288
+ * ```
1289
+ */
1290
+ async documentFacts(documentId) {
1291
+ const response = await this.http.request({
1292
+ method: "GET",
1293
+ path: `/api/v1/knowledge/documents/${documentId}/facts`
1294
+ });
1295
+ return response.data;
1296
+ }
1297
+ };
1298
+
1299
+ // src/modules/onboarding.ts
1300
+ var OnboardingModule = class {
1301
+ constructor(http) {
1302
+ this.http = http;
1303
+ }
1304
+ /**
1305
+ * Retrieve the onboarding status checklist for the authenticated company.
1306
+ *
1307
+ * Use this to determine what setup steps remain before going live.
1308
+ *
1309
+ * @example
1310
+ * ```typescript
1311
+ * const status = await client.onboarding.status();
1312
+ *
1313
+ * if (!status.quoteReady) {
1314
+ * console.log('Next step:', status.nextStep?.action);
1315
+ * }
1316
+ *
1317
+ * if (status.sandbox) {
1318
+ * console.log('Running in sandbox mode — upgrade to submit live quotes.');
1319
+ * }
1320
+ * ```
1321
+ */
1322
+ async status() {
1323
+ const response = await this.http.request({
1324
+ method: "GET",
1325
+ path: "/api/v1/onboarding/status"
1326
+ });
1327
+ return response.data;
1328
+ }
1329
+ };
1330
+
1331
+ // src/client.ts
1332
+ var API_KEY_REGEX = /^dlg_[a-zA-Z0-9]{8}_sk_[a-zA-Z0-9]{32}$/;
1333
+ var DeleganceClient = class {
1334
+ /**
1335
+ * Create a new Delegance client
1336
+ *
1337
+ * @param config - Client configuration
1338
+ * @throws Error if API key is missing or invalid format
1339
+ */
1340
+ constructor(config) {
1341
+ if (!config.apiKey) {
1342
+ throw new Error("API key is required. Get one from the Delegance dashboard.");
1343
+ }
1344
+ if (!API_KEY_REGEX.test(config.apiKey)) {
1345
+ throw new Error(
1346
+ "Invalid API key format. Expected format: dlg_xxxxxxxx_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
1347
+ );
1348
+ }
1349
+ this.http = new HttpClient(config);
1350
+ this.companies = new CompaniesModule(this.http);
1351
+ this.documents = new DocumentsModule(this.http);
1352
+ this.chat = new ChatModule(this.http);
1353
+ this.quotes = new QuotesModule(this.http);
1354
+ this.policies = new PoliciesModule(this.http);
1355
+ this.coi = new COIModule(this.http);
1356
+ this.sov = new SOVModule(this.http);
1357
+ this.apiKeys = new ApiKeysModule(this.http);
1358
+ this.usage = new UsageModule(this.http);
1359
+ this.knowledge = new KnowledgeModule(this.http);
1360
+ this.onboarding = new OnboardingModule(this.http);
1361
+ }
1362
+ /**
1363
+ * Get the SDK version
1364
+ */
1365
+ static get version() {
1366
+ return SDK_VERSION;
1367
+ }
1368
+ /**
1369
+ * Verify the API key is valid by making a test request
1370
+ *
1371
+ * @example
1372
+ * ```typescript
1373
+ * const isValid = await client.verifyApiKey();
1374
+ * if (!isValid) {
1375
+ * console.error('API key is invalid or expired');
1376
+ * }
1377
+ * ```
1378
+ */
1379
+ async verifyApiKey() {
1380
+ try {
1381
+ await this.companies.list();
1382
+ return true;
1383
+ } catch {
1384
+ return false;
1385
+ }
1386
+ }
1387
+ };
1388
+ function createClientFromEnv() {
1389
+ const apiKey = process.env.DELEGANCE_API_KEY;
1390
+ const baseUrl = process.env.DELEGANCE_BASE_URL;
1391
+ if (!apiKey) {
1392
+ throw new Error(
1393
+ "DELEGANCE_API_KEY environment variable is required. Get an API key from the Delegance dashboard."
1394
+ );
1395
+ }
1396
+ return new DeleganceClient({
1397
+ apiKey,
1398
+ baseUrl
1399
+ });
1400
+ }
1401
+ export {
1402
+ ApiKeysModule,
1403
+ AuthenticationError,
1404
+ COIModule,
1405
+ ChatModule,
1406
+ CompaniesModule,
1407
+ CompanySizeSchema,
1408
+ CreateCompanySchema,
1409
+ DeleganceClient,
1410
+ DeleganceError,
1411
+ DocumentStatusSchema,
1412
+ DocumentTypeSchema,
1413
+ DocumentsModule,
1414
+ KnowledgeModule,
1415
+ NotFoundError,
1416
+ OnboardingModule,
1417
+ PoliciesModule,
1418
+ QuotesModule,
1419
+ RateLimitError,
1420
+ SDK_VERSION,
1421
+ SOVModule,
1422
+ UsageModule,
1423
+ ValidationError,
1424
+ createClientFromEnv
1425
+ };