@delegance/sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -20,35 +20,53 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ API_KEY_SCOPES: () => API_KEY_SCOPES,
23
24
  ApiKeysModule: () => ApiKeysModule,
25
+ AppetiteModule: () => AppetiteModule,
26
+ AuthModule: () => AuthModule,
24
27
  AuthenticationError: () => AuthenticationError,
28
+ BondsModule: () => BondsModule,
25
29
  COIModule: () => COIModule,
26
30
  ChatModule: () => ChatModule,
31
+ ClaimsModule: () => ClaimsModule,
27
32
  CompaniesModule: () => CompaniesModule,
28
33
  CompanySizeSchema: () => CompanySizeSchema,
29
34
  CreateCompanySchema: () => CreateCompanySchema,
35
+ DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
30
36
  DeleganceClient: () => DeleganceClient,
31
37
  DeleganceError: () => DeleganceError,
38
+ DeviceLoginModule: () => DeviceLoginModule,
32
39
  DocumentStatusSchema: () => DocumentStatusSchema,
33
40
  DocumentTypeSchema: () => DocumentTypeSchema,
34
41
  DocumentsModule: () => DocumentsModule,
42
+ FEEDBACK_MESSAGE_MAX: () => FEEDBACK_MESSAGE_MAX,
43
+ FeedbackModule: () => FeedbackModule,
44
+ ForbiddenError: () => ForbiddenError,
45
+ InstantQuotesModule: () => InstantQuotesModule,
35
46
  KnowledgeModule: () => KnowledgeModule,
47
+ LeadsModule: () => LeadsModule,
36
48
  NotFoundError: () => NotFoundError,
49
+ NotImplementedError: () => NotImplementedError,
37
50
  OnboardingModule: () => OnboardingModule,
51
+ PaymentsModule: () => PaymentsModule,
38
52
  PoliciesModule: () => PoliciesModule,
39
53
  QuotesModule: () => QuotesModule,
40
54
  RateLimitError: () => RateLimitError,
41
55
  SDK_VERSION: () => SDK_VERSION,
42
56
  SOVModule: () => SOVModule,
57
+ SignupModule: () => SignupModule,
43
58
  UsageModule: () => UsageModule,
44
59
  ValidationError: () => ValidationError,
45
- createClientFromEnv: () => createClientFromEnv
60
+ createClientFromEnv: () => createClientFromEnv,
61
+ createDeviceLogin: () => createDeviceLogin,
62
+ createSignup: () => createSignup,
63
+ newDeviceSecret: () => newDeviceSecret
46
64
  });
47
65
  module.exports = __toCommonJS(index_exports);
48
66
 
49
67
  // src/types/index.ts
50
68
  var import_zod = require("zod");
51
- var CompanySizeSchema = import_zod.z.enum(["1", "2-10", "11-25", "26-50", "51-100", "100-499", "500+"]);
69
+ var CompanySizeSchema = import_zod.z.enum(["0", "1", "2-10", "11-25", "26-50", "51-100", "100-499", "500+"]);
52
70
  var CreateCompanySchema = import_zod.z.object({
53
71
  name: import_zod.z.string().min(1).max(255),
54
72
  legalName: import_zod.z.string().max(255).optional(),
@@ -70,7 +88,7 @@ var CreateCompanySchema = import_zod.z.object({
70
88
  zip: import_zod.z.string().regex(/^\d{5}(-\d{4})?$/)
71
89
  }).optional(),
72
90
  externalId: import_zod.z.string().max(255).optional(),
73
- metadata: import_zod.z.record(import_zod.z.unknown()).optional()
91
+ metadata: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
74
92
  });
75
93
  var DocumentTypeSchema = import_zod.z.enum([
76
94
  "policy",
@@ -125,13 +143,29 @@ var RateLimitError = class extends DeleganceError {
125
143
  this.name = "RateLimitError";
126
144
  }
127
145
  };
146
+ var ForbiddenError = class extends DeleganceError {
147
+ constructor(message, traceId) {
148
+ super(message, 403, traceId);
149
+ this.name = "ForbiddenError";
150
+ }
151
+ };
152
+ var NotImplementedError = class extends DeleganceError {
153
+ constructor(message, traceId) {
154
+ super(message, 501, traceId);
155
+ this.name = "NotImplementedError";
156
+ }
157
+ };
128
158
 
129
159
  // src/utils/http.ts
130
- var SDK_VERSION = "0.1.0";
160
+ var SDK_VERSION = "0.2.0";
161
+ var DEFAULT_BASE_URL = "https://portal.delegancebrokerage.com";
162
+ function isRetryableStatus(status) {
163
+ return status >= 500 && status !== 501;
164
+ }
131
165
  var HttpClient = class {
132
166
  constructor(config) {
133
167
  this.config = {
134
- baseUrl: (config.baseUrl || "https://app.delegance.ai").replace(/\/$/, ""),
168
+ baseUrl: (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, ""),
135
169
  apiKey: config.apiKey,
136
170
  timeout: config.timeout || 3e4,
137
171
  retries: config.retries ?? 3,
@@ -142,7 +176,8 @@ var HttpClient = class {
142
176
  const { method, path, body, headers = {}, timeout, isFormData } = options;
143
177
  const url = `${this.config.baseUrl}${path}`;
144
178
  const requestHeaders = {
145
- "Authorization": `Bearer ${this.config.apiKey}`,
179
+ // No key = an unauthenticated call (signup, the key exchange).
180
+ ...this.config.apiKey ? { "Authorization": `Bearer ${this.config.apiKey}` } : {},
146
181
  "User-Agent": `delegance-sdk/${SDK_VERSION}`,
147
182
  ...this.config.headers,
148
183
  ...headers
@@ -205,6 +240,7 @@ var HttpClient = class {
205
240
  */
206
241
  async executeWithRetry(buildRequest, timeoutMs) {
207
242
  let lastError = null;
243
+ let lastInformative = null;
208
244
  let attempts = 0;
209
245
  while (attempts <= this.config.retries) {
210
246
  const controller = new AbortController();
@@ -213,21 +249,34 @@ var HttpClient = class {
213
249
  const { url, init } = buildRequest();
214
250
  const response = await fetch(url, { ...init, signal: controller.signal });
215
251
  const data = await response.json().catch(() => ({}));
216
- const traceId = data.traceId;
252
+ const { traceId } = data;
217
253
  if (!response.ok) {
218
- throw this.handleErrorResponse(response.status, data, traceId);
254
+ const err = this.handleErrorResponse(response.status, data, traceId);
255
+ if (typeof data.reason === "string") err.reason = data.reason;
256
+ if (data && typeof data === "object") err.body = data;
257
+ if (err instanceof RateLimitError && err.retryAfter === void 0) {
258
+ const header = Number(response.headers?.get?.("Retry-After"));
259
+ if (Number.isFinite(header) && header > 0) err.retryAfter = header;
260
+ }
261
+ throw err;
219
262
  }
220
263
  return data;
221
264
  } catch (error) {
222
265
  lastError = error;
223
- if (error instanceof AuthenticationError || error instanceof ValidationError || error instanceof NotFoundError || error instanceof RateLimitError) {
266
+ if (error instanceof DeleganceError && error.message && error.message !== "Unknown error") {
267
+ lastInformative = error;
268
+ }
269
+ if (error instanceof DeleganceError && (!isRetryableStatus(error.statusCode) || error.reason === "not_available")) {
224
270
  throw error;
225
271
  }
226
272
  if (attempts < this.config.retries) {
227
273
  attempts++;
228
- await this.delay(Math.pow(2, attempts) * 1e3);
274
+ await this.delay(2 ** attempts * 1e3);
229
275
  continue;
230
276
  }
277
+ if (error instanceof DeleganceError && error.message === "Unknown error" && lastInformative) {
278
+ throw lastInformative;
279
+ }
231
280
  throw error;
232
281
  } finally {
233
282
  clearTimeout(timeoutId);
@@ -237,12 +286,14 @@ var HttpClient = class {
237
286
  }
238
287
  handleErrorResponse(status, data, traceId) {
239
288
  const message = data.message || data.error || "Unknown error";
240
- const details = data.details;
289
+ const { details } = data;
241
290
  switch (status) {
242
291
  case 401:
243
292
  return new AuthenticationError(message, traceId);
244
293
  case 400:
245
294
  return new ValidationError(message, details, traceId);
295
+ case 403:
296
+ return new ForbiddenError(message, traceId);
246
297
  case 404:
247
298
  return new NotFoundError(message, traceId);
248
299
  case 429:
@@ -251,6 +302,8 @@ var HttpClient = class {
251
302
  data.retryAfter,
252
303
  traceId
253
304
  );
305
+ case 501:
306
+ return new NotImplementedError(message, traceId);
254
307
  default:
255
308
  return new DeleganceError(message, status, traceId, details);
256
309
  }
@@ -852,6 +905,7 @@ var QuotesModule = class {
852
905
  };
853
906
 
854
907
  // src/modules/policies.ts
908
+ var import_crypto = require("crypto");
855
909
  var PoliciesModule = class {
856
910
  constructor(http) {
857
911
  this.http = http;
@@ -916,6 +970,40 @@ var PoliciesModule = class {
916
970
  throw error;
917
971
  }
918
972
  }
973
+ /**
974
+ * Ask to cancel a policy. The request waits for the insured's signature,
975
+ * collected at `signatureUrl` by an owner or admin; a broker reviews the
976
+ * claims-made continuity check before anything reaches the carrier.
977
+ */
978
+ async requestCancellation(policyId, input, opts = {}) {
979
+ return this.http.request({
980
+ method: "POST",
981
+ path: `/api/v1/policies/${encodeURIComponent(policyId)}/cancellation`,
982
+ body: input,
983
+ headers: { "Idempotency-Key": opts.idempotencyKey ?? (0, import_crypto.randomUUID)() }
984
+ });
985
+ }
986
+ /**
987
+ * Sign a cancellation request as an owner or admin. Signing needs a step-up
988
+ * code: call once without `code` to email it (202 with `stepUpId`), then
989
+ * again with `stepUpId` and `code`.
990
+ */
991
+ async signCancellation(requestId, input, opts = {}) {
992
+ return this.http.request({
993
+ method: "POST",
994
+ path: `/api/v1/policy-cancellations/${encodeURIComponent(requestId)}/sign`,
995
+ body: input,
996
+ headers: { "Idempotency-Key": opts.idempotencyKey ?? (0, import_crypto.randomUUID)() }
997
+ });
998
+ }
999
+ /** One cancellation request's status. */
1000
+ async getCancellation(requestId) {
1001
+ const res = await this.http.request({
1002
+ method: "GET",
1003
+ path: `/api/v1/policy-cancellations/${encodeURIComponent(requestId)}`
1004
+ });
1005
+ return res.request;
1006
+ }
919
1007
  };
920
1008
 
921
1009
  // src/modules/coi.ts
@@ -1071,6 +1159,7 @@ var SOVModule = class {
1071
1159
  };
1072
1160
 
1073
1161
  // src/modules/api-keys.ts
1162
+ var API_KEY_SCOPES = ["read", "write", "admin", "appetite:read", "mcp:read", "mcp:orin"];
1074
1163
  var ApiKeysModule = class {
1075
1164
  constructor(http) {
1076
1165
  this.http = http;
@@ -1183,8 +1272,18 @@ var ApiKeysModule = class {
1183
1272
  if (idempotency?.idempotencyKey) {
1184
1273
  requestOptions.headers = { "Idempotency-Key": idempotency.idempotencyKey };
1185
1274
  }
1186
- const response = await this.http.request(requestOptions);
1187
- return response.data;
1275
+ try {
1276
+ const response = await this.http.request(requestOptions);
1277
+ return response.data;
1278
+ } catch (error) {
1279
+ if (error instanceof NotFoundError) {
1280
+ throw new NotImplementedError(
1281
+ "Server-side key rotation is not available yet. Create a replacement key with apiKeys.create() using the same scopes, then revoke the old key in the portal.",
1282
+ error.traceId
1283
+ );
1284
+ }
1285
+ throw error;
1286
+ }
1188
1287
  }
1189
1288
  };
1190
1289
 
@@ -1374,6 +1473,519 @@ var OnboardingModule = class {
1374
1473
  });
1375
1474
  return response.data;
1376
1475
  }
1476
+ /** Poll the canonical onboarding state machine. Callable pre-verification. */
1477
+ async state() {
1478
+ const response = await this.http.request({
1479
+ method: "GET",
1480
+ path: "/api/v1/onboarding/state"
1481
+ });
1482
+ return response.data;
1483
+ }
1484
+ /**
1485
+ * Issue (or re-issue) the human verification challenge. Delegance emails a
1486
+ * confirmation link to the company contact email. Hand that link to a human;
1487
+ * the agent cannot self-verify.
1488
+ */
1489
+ async requestVerification() {
1490
+ const response = await this.http.request({
1491
+ method: "POST",
1492
+ path: "/api/v1/onboarding/verification"
1493
+ });
1494
+ return { state: response.data.state, sentTo: response.data.sentTo };
1495
+ }
1496
+ /** Poll state() until `target` is reached or `timeoutMs` elapses. */
1497
+ async waitForState(target, options = {}) {
1498
+ const intervalMs = options.intervalMs ?? 5e3;
1499
+ const timeoutMs = options.timeoutMs ?? 10 * 60 * 1e3;
1500
+ if (!Number.isFinite(intervalMs) || intervalMs <= 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) {
1501
+ throw new ValidationError("intervalMs and timeoutMs must be positive numbers");
1502
+ }
1503
+ const deadline = Date.now() + timeoutMs;
1504
+ for (; ; ) {
1505
+ const current = await this.state();
1506
+ if (current.state === target) return current;
1507
+ if (Date.now() + intervalMs > deadline) {
1508
+ throw new Error(
1509
+ `waitForState('${target}') timed out after ${timeoutMs}ms (last state: ${current.state})`
1510
+ );
1511
+ }
1512
+ await new Promise((r) => setTimeout(r, intervalMs));
1513
+ }
1514
+ }
1515
+ };
1516
+
1517
+ // src/modules/appetite.ts
1518
+ function withoutEnvelope(response) {
1519
+ const copy = { ...response };
1520
+ delete copy.success;
1521
+ return copy;
1522
+ }
1523
+ var AppetiteModule = class {
1524
+ constructor(http) {
1525
+ this.http = http;
1526
+ }
1527
+ /**
1528
+ * Start an appetite match. Returns the result directly on a warm cache hit,
1529
+ * or a queued job to poll with `getMatch()`.
1530
+ *
1531
+ * @example
1532
+ * ```typescript
1533
+ * const start = await client.appetite.match({ state: 'CA', industry: 'restaurant' });
1534
+ * const result = start.status === 'succeeded'
1535
+ * ? start
1536
+ * : await client.appetite.waitForMatch(start.jobId);
1537
+ * ```
1538
+ */
1539
+ async match(input) {
1540
+ if (!input.state || input.state.trim().length !== 2) {
1541
+ throw new ValidationError("state must be a two-letter code");
1542
+ }
1543
+ if (!input.industry && !input.businessDescription && !input.naicsCode && !input.sicCode) {
1544
+ throw new ValidationError("One of industry, businessDescription, naicsCode, or sicCode is required");
1545
+ }
1546
+ const response = await this.http.request({
1547
+ method: "POST",
1548
+ path: "/api/v1/appetite/match",
1549
+ body: input
1550
+ });
1551
+ if (typeof response.jobId === "string" && typeof response.statusUrl === "string") {
1552
+ return {
1553
+ status: "queued",
1554
+ jobId: response.jobId,
1555
+ statusUrl: response.statusUrl,
1556
+ estimatedSeconds: response.estimatedSeconds ?? 20,
1557
+ traceId: response.traceId
1558
+ };
1559
+ }
1560
+ return {
1561
+ ...withoutEnvelope(response),
1562
+ status: "succeeded",
1563
+ cached: true,
1564
+ jobId: null,
1565
+ traceId: response.traceId
1566
+ };
1567
+ }
1568
+ /** Read a match job. Unknown, expired, and other-tenant ids all raise NotFoundError. */
1569
+ async getMatch(jobId) {
1570
+ const response = await this.http.request({
1571
+ method: "GET",
1572
+ path: `/api/v1/appetite/match/${encodeURIComponent(jobId)}`
1573
+ });
1574
+ return withoutEnvelope(response);
1575
+ }
1576
+ /**
1577
+ * Poll a job until it succeeds. Throws on a failed job (with the sanitized
1578
+ * errorCode) or on timeout.
1579
+ */
1580
+ async waitForMatch(jobId, options = {}) {
1581
+ const intervalMs = options.intervalMs ?? 3e3;
1582
+ const timeoutMs = options.timeoutMs ?? 2 * 60 * 1e3;
1583
+ if (!Number.isFinite(intervalMs) || intervalMs <= 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) {
1584
+ throw new ValidationError("intervalMs and timeoutMs must be positive numbers");
1585
+ }
1586
+ const deadline = Date.now() + timeoutMs;
1587
+ for (; ; ) {
1588
+ const job = await this.getMatch(jobId);
1589
+ if (job.status === "succeeded") return job;
1590
+ if (job.status === "failed") {
1591
+ throw new DeleganceError(
1592
+ `Appetite match failed: ${job.errorCode}${job.retryable ? " (retryable)" : ""}`,
1593
+ 500,
1594
+ job.traceId
1595
+ );
1596
+ }
1597
+ if (Date.now() + intervalMs > deadline) {
1598
+ throw new DeleganceError(`Appetite match ${jobId} still ${job.status} after ${timeoutMs}ms`, 408);
1599
+ }
1600
+ await new Promise((r) => setTimeout(r, intervalMs));
1601
+ }
1602
+ }
1603
+ };
1604
+
1605
+ // src/modules/leads.ts
1606
+ var LeadsModule = class {
1607
+ constructor(http) {
1608
+ this.http = http;
1609
+ }
1610
+ /**
1611
+ * Create a lead.
1612
+ *
1613
+ * @example
1614
+ * ```typescript
1615
+ * const { companyId } = await client.leads.create({
1616
+ * name: 'Riverbend Bakery',
1617
+ * contactEmail: 'owner@riverbend.example',
1618
+ * state: 'TX',
1619
+ * externalId: 'crm-4411',
1620
+ * });
1621
+ * ```
1622
+ */
1623
+ async create(input) {
1624
+ return this.http.request({
1625
+ method: "POST",
1626
+ path: "/api/v1/leads",
1627
+ body: input
1628
+ });
1629
+ }
1630
+ };
1631
+
1632
+ // src/modules/instant-quotes.ts
1633
+ var import_crypto2 = require("crypto");
1634
+ var InstantQuotesModule = class {
1635
+ constructor(http) {
1636
+ this.http = http;
1637
+ }
1638
+ /**
1639
+ * `fresh: true` always mints a new submission instead of reusing a warm
1640
+ * session for the same coverages. Use it with `submit({ replace: true })`
1641
+ * to re-quote coverage that already has a request with carriers.
1642
+ */
1643
+ async start(coverages, opts = {}) {
1644
+ const res = await this.http.request({
1645
+ method: "POST",
1646
+ path: "/api/v1/quotes/instant/session",
1647
+ body: opts.fresh ? { coverages, fresh: true } : { coverages }
1648
+ });
1649
+ return res.data;
1650
+ }
1651
+ async submit(input, opts = {}) {
1652
+ const res = await this.http.request({
1653
+ method: "POST",
1654
+ path: "/api/v1/quotes/instant/submit",
1655
+ body: input,
1656
+ headers: { "Idempotency-Key": opts.idempotencyKey ?? (0, import_crypto2.randomUUID)() }
1657
+ });
1658
+ return res.data;
1659
+ }
1660
+ async status(submissionId) {
1661
+ const res = await this.http.request({
1662
+ method: "GET",
1663
+ path: `/api/v1/quotes/instant/${encodeURIComponent(submissionId)}`
1664
+ });
1665
+ return res.data;
1666
+ }
1667
+ /** Polls `status` until every visible carrier resolved, or the timeout. */
1668
+ async waitForQuotes(submissionId, opts = {}) {
1669
+ const timeoutMs = opts.timeoutMs ?? 10 * 60 * 1e3;
1670
+ const intervalMs = opts.intervalMs ?? 1e4;
1671
+ const deadline = Date.now() + timeoutMs;
1672
+ for (; ; ) {
1673
+ const s = await this.status(submissionId);
1674
+ opts.onPoll?.(s);
1675
+ const remaining = deadline - Date.now();
1676
+ if (s.allCarriersResolved || remaining <= 0) return s;
1677
+ await new Promise((resolve) => setTimeout(resolve, Math.min(intervalMs, remaining)));
1678
+ }
1679
+ }
1680
+ /**
1681
+ * After a `no_carriers` submit: the ACORD questions a broker needs to place
1682
+ * the risk with a non-instant market. Pass the answers you submitted so
1683
+ * facts you already gave are not asked again.
1684
+ */
1685
+ async brokerHandoffQuestions(submissionId, instantAnswers = {}) {
1686
+ const res = await this.http.request({
1687
+ method: "POST",
1688
+ path: `/api/v1/quotes/instant/${encodeURIComponent(submissionId)}/broker-handoff/questions`,
1689
+ body: { instantAnswers }
1690
+ });
1691
+ return res.data;
1692
+ }
1693
+ /**
1694
+ * Hands a `no_carriers` submission to a Delegance broker as a non-instant
1695
+ * request, with whatever ACORD answers you have. `complete: false` says you
1696
+ * stopped early; the broker asks the rest. A repeat call returns the same
1697
+ * broker task.
1698
+ */
1699
+ async brokerHandoff(submissionId, input, opts = {}) {
1700
+ const res = await this.http.request({
1701
+ method: "POST",
1702
+ path: `/api/v1/quotes/instant/${encodeURIComponent(submissionId)}/broker-handoff`,
1703
+ body: input,
1704
+ headers: { "Idempotency-Key": opts.idempotencyKey ?? (0, import_crypto2.randomUUID)() }
1705
+ });
1706
+ return res.data;
1707
+ }
1708
+ /** Requests a bind on one offer. A licensed broker reviews it; nothing is charged. */
1709
+ async bind(submissionId, opportunityId, opts = {}) {
1710
+ const res = await this.http.request({
1711
+ method: "POST",
1712
+ path: `/api/v1/quotes/instant/${encodeURIComponent(submissionId)}/bind`,
1713
+ body: { opportunityId },
1714
+ headers: { "Idempotency-Key": opts.idempotencyKey ?? (0, import_crypto2.randomUUID)() }
1715
+ });
1716
+ return res.data;
1717
+ }
1718
+ /**
1719
+ * Bind through fast bind: an owner or admin attests the answers, gets a
1720
+ * 6-digit code by email (the first call returns `stepUpRequired`), then calls
1721
+ * again with `stepUpId` and `code`. A tier A offer returns `checkoutUrl`;
1722
+ * any other offer goes to a broker.
1723
+ */
1724
+ async bindWithStepUp(submissionId, opportunityId, input = {}) {
1725
+ const { idempotencyKey, ...rest } = input;
1726
+ const res = await this.http.request({
1727
+ method: "POST",
1728
+ path: `/api/v1/quotes/instant/${encodeURIComponent(submissionId)}/bind`,
1729
+ body: { opportunityId, ...rest },
1730
+ headers: { "Idempotency-Key": idempotencyKey ?? (0, import_crypto2.randomUUID)() }
1731
+ });
1732
+ if (res.stepUpRequired && res.stepUpId) {
1733
+ return { stepUpRequired: true, stepUpId: res.stepUpId, channel: "email", sentTo: res.sentTo ?? "", expiresAt: res.expiresAt ?? null };
1734
+ }
1735
+ return res.data;
1736
+ }
1737
+ };
1738
+
1739
+ // src/modules/payments.ts
1740
+ var import_crypto3 = require("crypto");
1741
+ var PaymentsModule = class {
1742
+ constructor(http) {
1743
+ this.http = http;
1744
+ }
1745
+ async list() {
1746
+ const res = await this.http.request({ method: "GET", path: "/api/v1/payments" });
1747
+ return res.data.payments;
1748
+ }
1749
+ async checkout(paymentRequestId, opts = {}) {
1750
+ const res = await this.http.request({
1751
+ method: "POST",
1752
+ path: `/api/v1/payments/${encodeURIComponent(paymentRequestId)}/checkout`,
1753
+ headers: { "Idempotency-Key": opts.idempotencyKey ?? (0, import_crypto3.randomUUID)() }
1754
+ });
1755
+ return res.data;
1756
+ }
1757
+ };
1758
+
1759
+ // src/modules/bonds.ts
1760
+ var import_crypto4 = require("crypto");
1761
+ var BondsModule = class {
1762
+ constructor(http) {
1763
+ this.http = http;
1764
+ }
1765
+ async start(input) {
1766
+ const res = await this.http.request({ method: "POST", path: "/api/v1/bonds/quote", body: input });
1767
+ return res.data;
1768
+ }
1769
+ async answer(sessionId, answers, opts = {}) {
1770
+ const res = await this.http.request({
1771
+ method: "POST",
1772
+ path: `/api/v1/bonds/quote/${encodeURIComponent(sessionId)}/answers`,
1773
+ body: { answers },
1774
+ headers: { "Idempotency-Key": opts.idempotencyKey ?? (0, import_crypto4.randomUUID)() }
1775
+ });
1776
+ return res.data;
1777
+ }
1778
+ async status(sessionId) {
1779
+ const res = await this.http.request({
1780
+ method: "GET",
1781
+ path: `/api/v1/bonds/quote/${encodeURIComponent(sessionId)}`
1782
+ });
1783
+ return res.data;
1784
+ }
1785
+ };
1786
+
1787
+ // src/modules/claims.ts
1788
+ var import_crypto5 = require("crypto");
1789
+ var ClaimsModule = class {
1790
+ constructor(http) {
1791
+ this.http = http;
1792
+ }
1793
+ async file(input, opts = {}) {
1794
+ const res = await this.http.request({
1795
+ method: "POST",
1796
+ path: "/api/v1/claims",
1797
+ body: input,
1798
+ headers: { "Idempotency-Key": opts.idempotencyKey ?? (0, import_crypto5.randomUUID)() }
1799
+ });
1800
+ return res.data;
1801
+ }
1802
+ async list(opts = {}) {
1803
+ const q = new URLSearchParams();
1804
+ if (opts.status) q.set("status", opts.status);
1805
+ if (opts.limit) q.set("limit", String(opts.limit));
1806
+ const qs = q.toString();
1807
+ const res = await this.http.request({ method: "GET", path: `/api/v1/claims${qs ? `?${qs}` : ""}` });
1808
+ return res.data.claims;
1809
+ }
1810
+ async get(claimId) {
1811
+ const res = await this.http.request({ method: "GET", path: `/api/v1/claims/${encodeURIComponent(claimId)}` });
1812
+ return res.data;
1813
+ }
1814
+ };
1815
+
1816
+ // src/modules/feedback.ts
1817
+ var import_crypto6 = require("crypto");
1818
+ var FEEDBACK_MESSAGE_MAX = 500;
1819
+ var FeedbackModule = class {
1820
+ constructor(http) {
1821
+ this.http = http;
1822
+ }
1823
+ /**
1824
+ * File a report. Returns the reference id Delegance uses to find it.
1825
+ *
1826
+ * Each call sends one Idempotency-Key, and the client's automatic retries of
1827
+ * that call reuse it, so a lost response never files the report twice. Pass
1828
+ * your own key to make a retry of your own (a second call) safe as well.
1829
+ */
1830
+ async submit(input, opts = {}) {
1831
+ const message = (input.message ?? "").trim();
1832
+ if (!message) throw new Error("Feedback needs a message.");
1833
+ if (message.length > FEEDBACK_MESSAGE_MAX) {
1834
+ throw new Error(`Keep the message to ${FEEDBACK_MESSAGE_MAX} characters or fewer.`);
1835
+ }
1836
+ const body = { type: input.type ?? "bug", message };
1837
+ if (input.context && Object.keys(input.context).length > 0) body.context = input.context;
1838
+ const res = await this.http.request({
1839
+ method: "POST",
1840
+ path: "/api/v1/feedback",
1841
+ body,
1842
+ headers: { "Idempotency-Key": opts.idempotencyKey ?? (0, import_crypto6.randomUUID)() }
1843
+ });
1844
+ return { id: res.data.id };
1845
+ }
1846
+ };
1847
+
1848
+ // src/modules/signup.ts
1849
+ var import_crypto7 = require("crypto");
1850
+
1851
+ // src/utils/poll.ts
1852
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1853
+ async function pollUntilReady(poll, opts = {}) {
1854
+ const timeoutMs = opts.timeoutMs ?? 15 * 60 * 1e3;
1855
+ const intervalMs = opts.intervalMs ?? 5e3;
1856
+ const deadline = Date.now() + timeoutMs;
1857
+ for (; ; ) {
1858
+ let wait = intervalMs;
1859
+ try {
1860
+ const r = await poll();
1861
+ if (r.status !== "pending") return r;
1862
+ } catch (err) {
1863
+ if (!(err instanceof RateLimitError)) throw err;
1864
+ wait = Math.max(intervalMs, (err.retryAfter ?? 60) * 1e3);
1865
+ }
1866
+ opts.onPoll?.();
1867
+ const remaining = deadline - Date.now();
1868
+ if (remaining <= 0) return { status: "pending" };
1869
+ await sleep(Math.min(wait, remaining));
1870
+ }
1871
+ }
1872
+
1873
+ // src/modules/signup.ts
1874
+ function newDeviceSecret() {
1875
+ const secret = (0, import_crypto7.randomBytes)(32).toString("hex");
1876
+ return { secret, hash: (0, import_crypto7.createHash)("sha256").update(secret).digest("hex") };
1877
+ }
1878
+ var SignupModule = class {
1879
+ constructor(makeHttp) {
1880
+ this.makeHttp = makeHttp;
1881
+ }
1882
+ /** Creates the unverified company. Retries safely: sends an Idempotency-Key. */
1883
+ async createAccount(input, opts = {}) {
1884
+ const res = await this.makeHttp("").request({
1885
+ method: "POST",
1886
+ path: "/api/v1/companies",
1887
+ body: input,
1888
+ headers: { "Idempotency-Key": opts.idempotencyKey ?? (0, import_crypto7.randomUUID)() }
1889
+ });
1890
+ if (!res.bootstrapKey) {
1891
+ throw new Error("The signup was already created by an earlier attempt; its key is shown only once. Start again with a new signup.");
1892
+ }
1893
+ return {
1894
+ companyId: res.company.id,
1895
+ bootstrapKey: res.bootstrapKey,
1896
+ ...res.warnings?.length ? { warnings: res.warnings } : {}
1897
+ };
1898
+ }
1899
+ async enroll(bootstrapKey, input) {
1900
+ const res = await this.makeHttp(bootstrapKey).request({
1901
+ method: "POST",
1902
+ path: "/api/v1/onboarding/cli-enroll",
1903
+ body: input
1904
+ });
1905
+ return res.data;
1906
+ }
1907
+ async requestVerification(bootstrapKey) {
1908
+ const res = await this.makeHttp(bootstrapKey).request({
1909
+ method: "POST",
1910
+ path: "/api/v1/onboarding/verification",
1911
+ body: {}
1912
+ });
1913
+ return { sentTo: res.data?.sentTo };
1914
+ }
1915
+ /**
1916
+ * One poll. `pending` until the email link is clicked. Throws with
1917
+ * `reason` = already_collected | account_exists (409) or expired (410).
1918
+ */
1919
+ async exchange(enrollmentId, deviceSecret) {
1920
+ const res = await this.makeHttp("").request({
1921
+ method: "POST",
1922
+ path: "/api/v1/onboarding/cli-exchange",
1923
+ body: { enrollmentId, deviceSecret }
1924
+ });
1925
+ if (res.data?.apiKey && res.data.keyPrefix && res.data.companyId) {
1926
+ return { status: "ready", apiKey: res.data.apiKey, keyPrefix: res.data.keyPrefix, companyId: res.data.companyId };
1927
+ }
1928
+ if (res.data?.status === "pending") return { status: "pending" };
1929
+ throw new Error('Unexpected response from the key exchange. Run "delegance verify" to retry.');
1930
+ }
1931
+ /**
1932
+ * Polls `exchange` until the key is ready or `timeoutMs` passes. A 429 waits
1933
+ * the server's Retry-After and keeps polling.
1934
+ */
1935
+ async waitForKey(enrollmentId, deviceSecret, opts = {}) {
1936
+ return pollUntilReady(() => this.exchange(enrollmentId, deviceSecret), opts);
1937
+ }
1938
+ };
1939
+
1940
+ // src/modules/auth.ts
1941
+ var DeviceLoginModule = class {
1942
+ constructor(makeHttp) {
1943
+ this.makeHttp = makeHttp;
1944
+ }
1945
+ async start(input) {
1946
+ const res = await this.makeHttp("").request({
1947
+ method: "POST",
1948
+ path: "/api/v1/auth/device",
1949
+ body: input
1950
+ });
1951
+ return res.data;
1952
+ }
1953
+ /**
1954
+ * One poll. `pending` until the portal user approves. Throws with `reason`
1955
+ * = access_denied (403), already_collected (409), or expired (410).
1956
+ */
1957
+ async poll(loginId, deviceSecret) {
1958
+ const res = await this.makeHttp("").request({
1959
+ method: "POST",
1960
+ path: "/api/v1/auth/device/token",
1961
+ body: { loginId, deviceSecret }
1962
+ });
1963
+ const d = res.data ?? {};
1964
+ if (d.apiKey && d.keyPrefix && d.companyId) {
1965
+ return { status: "ready", apiKey: d.apiKey, keyPrefix: d.keyPrefix, companyId: d.companyId, scopes: d.scopes ?? [], expiresAt: d.expiresAt ?? null };
1966
+ }
1967
+ if (d.status === "pending") return { status: "pending" };
1968
+ throw new Error('Unexpected response from the login poll. Run "delegance auth login" again.');
1969
+ }
1970
+ /** Polls until the key is ready or `timeoutMs` passes (then returns `pending`). */
1971
+ async waitForKey(loginId, deviceSecret, opts = {}) {
1972
+ return pollUntilReady(() => this.poll(loginId, deviceSecret), opts);
1973
+ }
1974
+ };
1975
+ var AuthModule = class {
1976
+ constructor(http) {
1977
+ this.http = http;
1978
+ }
1979
+ /** The calling key: prefix, origin, scopes, company, and expiry. */
1980
+ async keyInfo() {
1981
+ const res = await this.http.request({ method: "GET", path: "/api/v1/auth/key" });
1982
+ return res.data;
1983
+ }
1984
+ /** Extend a CLI key to 90 days from now. Throws `not_refreshable` (400) for portal keys. */
1985
+ async refresh() {
1986
+ const res = await this.http.request({ method: "POST", path: "/api/v1/auth/refresh", body: {} });
1987
+ return res.data;
1988
+ }
1377
1989
  };
1378
1990
 
1379
1991
  // src/client.ts
@@ -1406,6 +2018,14 @@ var DeleganceClient = class {
1406
2018
  this.usage = new UsageModule(this.http);
1407
2019
  this.knowledge = new KnowledgeModule(this.http);
1408
2020
  this.onboarding = new OnboardingModule(this.http);
2021
+ this.appetite = new AppetiteModule(this.http);
2022
+ this.leads = new LeadsModule(this.http);
2023
+ this.instantQuotes = new InstantQuotesModule(this.http);
2024
+ this.payments = new PaymentsModule(this.http);
2025
+ this.bonds = new BondsModule(this.http);
2026
+ this.claims = new ClaimsModule(this.http);
2027
+ this.feedback = new FeedbackModule(this.http);
2028
+ this.auth = new AuthModule(this.http);
1409
2029
  }
1410
2030
  /**
1411
2031
  * Get the SDK version
@@ -1446,29 +2066,53 @@ function createClientFromEnv() {
1446
2066
  baseUrl
1447
2067
  });
1448
2068
  }
2069
+ function createSignup(config = {}) {
2070
+ return new SignupModule((apiKey) => new HttpClient({ apiKey, ...config }));
2071
+ }
2072
+ function createDeviceLogin(config = {}) {
2073
+ return new DeviceLoginModule((apiKey) => new HttpClient({ apiKey, ...config }));
2074
+ }
1449
2075
  // Annotate the CommonJS export names for ESM import in node:
1450
2076
  0 && (module.exports = {
2077
+ API_KEY_SCOPES,
1451
2078
  ApiKeysModule,
2079
+ AppetiteModule,
2080
+ AuthModule,
1452
2081
  AuthenticationError,
2082
+ BondsModule,
1453
2083
  COIModule,
1454
2084
  ChatModule,
2085
+ ClaimsModule,
1455
2086
  CompaniesModule,
1456
2087
  CompanySizeSchema,
1457
2088
  CreateCompanySchema,
2089
+ DEFAULT_BASE_URL,
1458
2090
  DeleganceClient,
1459
2091
  DeleganceError,
2092
+ DeviceLoginModule,
1460
2093
  DocumentStatusSchema,
1461
2094
  DocumentTypeSchema,
1462
2095
  DocumentsModule,
2096
+ FEEDBACK_MESSAGE_MAX,
2097
+ FeedbackModule,
2098
+ ForbiddenError,
2099
+ InstantQuotesModule,
1463
2100
  KnowledgeModule,
2101
+ LeadsModule,
1464
2102
  NotFoundError,
2103
+ NotImplementedError,
1465
2104
  OnboardingModule,
2105
+ PaymentsModule,
1466
2106
  PoliciesModule,
1467
2107
  QuotesModule,
1468
2108
  RateLimitError,
1469
2109
  SDK_VERSION,
1470
2110
  SOVModule,
2111
+ SignupModule,
1471
2112
  UsageModule,
1472
2113
  ValidationError,
1473
- createClientFromEnv
2114
+ createClientFromEnv,
2115
+ createDeviceLogin,
2116
+ createSignup,
2117
+ newDeviceSecret
1474
2118
  });