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