@businessdash/sdk 0.9.60 → 0.9.70

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.
Files changed (233) hide show
  1. package/README.md +1012 -186
  2. package/assets/biab-sw.js +92 -0
  3. package/dist/account-core/index.d.ts +126 -0
  4. package/dist/account-core/index.d.ts.map +1 -0
  5. package/dist/account-core/index.js +191 -0
  6. package/dist/account-core/index.js.map +1 -0
  7. package/dist/account.d.ts +11 -0
  8. package/dist/account.d.ts.map +1 -0
  9. package/dist/account.js +11 -0
  10. package/dist/account.js.map +1 -0
  11. package/dist/auth-handler.d.ts +1 -1
  12. package/dist/auth-links.d.ts +33 -0
  13. package/dist/auth-links.d.ts.map +1 -0
  14. package/dist/auth-links.js +64 -0
  15. package/dist/auth-links.js.map +1 -0
  16. package/dist/blog-core/index.d.ts +112 -0
  17. package/dist/blog-core/index.d.ts.map +1 -0
  18. package/dist/blog-core/index.js +330 -0
  19. package/dist/blog-core/index.js.map +1 -0
  20. package/dist/blog.d.ts +11 -0
  21. package/dist/blog.d.ts.map +1 -0
  22. package/dist/blog.js +11 -0
  23. package/dist/blog.js.map +1 -0
  24. package/dist/chat-core/index.d.ts +97 -0
  25. package/dist/chat-core/index.d.ts.map +1 -0
  26. package/dist/chat-core/index.js +237 -0
  27. package/dist/chat-core/index.js.map +1 -0
  28. package/dist/chat.d.ts +11 -0
  29. package/dist/chat.d.ts.map +1 -0
  30. package/dist/chat.js +11 -0
  31. package/dist/chat.js.map +1 -0
  32. package/dist/checkout-core/index.d.ts +65 -0
  33. package/dist/checkout-core/index.d.ts.map +1 -0
  34. package/dist/checkout-core/index.js +159 -0
  35. package/dist/checkout-core/index.js.map +1 -0
  36. package/dist/checkout.d.ts +10 -0
  37. package/dist/checkout.d.ts.map +1 -0
  38. package/dist/checkout.js +10 -0
  39. package/dist/checkout.js.map +1 -0
  40. package/dist/cli.js +133 -25
  41. package/dist/cli.js.map +1 -1
  42. package/dist/client.d.ts +567 -1
  43. package/dist/client.d.ts.map +1 -1
  44. package/dist/client.js +807 -1
  45. package/dist/client.js.map +1 -1
  46. package/dist/contracts.d.ts +3309 -761
  47. package/dist/contracts.d.ts.map +1 -1
  48. package/dist/contracts.js +541 -4
  49. package/dist/contracts.js.map +1 -1
  50. package/dist/data-model-schema.d.ts +1 -1
  51. package/dist/data-model-schema.d.ts.map +1 -1
  52. package/dist/element.d.ts +30 -0
  53. package/dist/element.d.ts.map +1 -1
  54. package/dist/element.js +56 -0
  55. package/dist/element.js.map +1 -1
  56. package/dist/embed-protocol.d.ts +86 -0
  57. package/dist/embed-protocol.d.ts.map +1 -0
  58. package/dist/embed-protocol.js +60 -0
  59. package/dist/embed-protocol.js.map +1 -0
  60. package/dist/framework-support.d.ts +122 -0
  61. package/dist/framework-support.d.ts.map +1 -0
  62. package/dist/framework-support.js +323 -0
  63. package/dist/framework-support.js.map +1 -0
  64. package/dist/index.cjs +1244 -5
  65. package/dist/legal-core/index.cjs +115 -0
  66. package/dist/legal-core/index.d.ts +160 -0
  67. package/dist/legal-core/index.d.ts.map +1 -0
  68. package/dist/legal-core/index.js +220 -0
  69. package/dist/legal-core/index.js.map +1 -0
  70. package/dist/marketing-core/index.d.ts +66 -0
  71. package/dist/marketing-core/index.d.ts.map +1 -0
  72. package/dist/marketing-core/index.js +154 -0
  73. package/dist/marketing-core/index.js.map +1 -0
  74. package/dist/marketing.d.ts +7 -0
  75. package/dist/marketing.d.ts.map +1 -0
  76. package/dist/marketing.js +7 -0
  77. package/dist/marketing.js.map +1 -0
  78. package/dist/mcp-adapters/index.d.ts +135 -0
  79. package/dist/mcp-adapters/index.d.ts.map +1 -0
  80. package/dist/mcp-adapters/index.js +187 -0
  81. package/dist/mcp-adapters/index.js.map +1 -0
  82. package/dist/mcp-adapters.d.ts +7 -0
  83. package/dist/mcp-adapters.d.ts.map +1 -0
  84. package/dist/mcp-adapters.js +7 -0
  85. package/dist/mcp-adapters.js.map +1 -0
  86. package/dist/model3d-core/index.cjs +95 -0
  87. package/dist/model3d-core/index.d.ts +167 -0
  88. package/dist/model3d-core/index.d.ts.map +1 -0
  89. package/dist/model3d-core/index.js +158 -0
  90. package/dist/model3d-core/index.js.map +1 -0
  91. package/dist/notifications-core/index.cjs +315 -0
  92. package/dist/notifications-core/index.d.ts +229 -0
  93. package/dist/notifications-core/index.d.ts.map +1 -0
  94. package/dist/notifications-core/index.js +445 -0
  95. package/dist/notifications-core/index.js.map +1 -0
  96. package/dist/portal-core/index.d.ts +451 -0
  97. package/dist/portal-core/index.d.ts.map +1 -0
  98. package/dist/portal-core/index.js +819 -0
  99. package/dist/portal-core/index.js.map +1 -0
  100. package/dist/portal.d.ts +7 -0
  101. package/dist/portal.d.ts.map +1 -0
  102. package/dist/portal.js +7 -0
  103. package/dist/portal.js.map +1 -0
  104. package/dist/push-core/index.cjs +171 -0
  105. package/dist/push-core/index.d.ts +149 -0
  106. package/dist/push-core/index.d.ts.map +1 -0
  107. package/dist/push-core/index.js +231 -0
  108. package/dist/push-core/index.js.map +1 -0
  109. package/dist/react-marketing.d.ts +1 -17
  110. package/dist/react-marketing.d.ts.map +1 -1
  111. package/dist/react-marketing.js +4 -0
  112. package/dist/react-marketing.js.map +1 -1
  113. package/dist/react.d.ts +294 -101
  114. package/dist/react.d.ts.map +1 -1
  115. package/dist/react.js +302 -246
  116. package/dist/react.js.map +1 -1
  117. package/dist/seed-core/index.d.ts +354 -0
  118. package/dist/seed-core/index.d.ts.map +1 -0
  119. package/dist/seed-core/index.js +420 -0
  120. package/dist/seed-core/index.js.map +1 -0
  121. package/dist/seed.d.ts +7 -0
  122. package/dist/seed.d.ts.map +1 -0
  123. package/dist/seed.js +7 -0
  124. package/dist/seed.js.map +1 -0
  125. package/dist/seo-core/blog.d.ts +94 -0
  126. package/dist/seo-core/blog.d.ts.map +1 -0
  127. package/dist/seo-core/blog.js +149 -0
  128. package/dist/seo-core/blog.js.map +1 -0
  129. package/dist/seo-core/commerce.d.ts +64 -0
  130. package/dist/seo-core/commerce.d.ts.map +1 -0
  131. package/dist/seo-core/commerce.js +87 -0
  132. package/dist/seo-core/commerce.js.map +1 -0
  133. package/dist/seo-core/index.cjs +751 -0
  134. package/dist/seo-core/index.d.ts +226 -0
  135. package/dist/seo-core/index.d.ts.map +1 -0
  136. package/dist/seo-core/index.js +455 -0
  137. package/dist/seo-core/index.js.map +1 -0
  138. package/dist/seo-core/local.d.ts +181 -0
  139. package/dist/seo-core/local.d.ts.map +1 -0
  140. package/dist/seo-core/local.js +193 -0
  141. package/dist/seo-core/local.js.map +1 -0
  142. package/dist/sitemap-core/index.cjs +167 -0
  143. package/dist/sitemap-core/index.d.ts +155 -0
  144. package/dist/sitemap-core/index.d.ts.map +1 -0
  145. package/dist/sitemap-core/index.js +195 -0
  146. package/dist/sitemap-core/index.js.map +1 -0
  147. package/dist/social-core/index.d.ts +74 -0
  148. package/dist/social-core/index.d.ts.map +1 -0
  149. package/dist/social-core/index.js +72 -0
  150. package/dist/social-core/index.js.map +1 -0
  151. package/dist/social.d.ts +7 -0
  152. package/dist/social.d.ts.map +1 -0
  153. package/dist/social.js +7 -0
  154. package/dist/social.js.map +1 -0
  155. package/dist/solid-compat.d.ts +204 -0
  156. package/dist/solid-compat.d.ts.map +1 -0
  157. package/dist/solid-compat.js +221 -0
  158. package/dist/solid-compat.js.map +1 -0
  159. package/dist/store-core/index.d.ts +141 -0
  160. package/dist/store-core/index.d.ts.map +1 -0
  161. package/dist/store-core/index.js +277 -0
  162. package/dist/store-core/index.js.map +1 -0
  163. package/dist/store.d.ts +12 -0
  164. package/dist/store.d.ts.map +1 -0
  165. package/dist/store.js +12 -0
  166. package/dist/store.js.map +1 -0
  167. package/dist/vanilla.d.ts +111 -0
  168. package/dist/vanilla.d.ts.map +1 -1
  169. package/dist/vanilla.js +206 -0
  170. package/dist/vanilla.js.map +1 -1
  171. package/dist/verify-core/index.d.ts +98 -0
  172. package/dist/verify-core/index.d.ts.map +1 -0
  173. package/dist/verify-core/index.js +186 -0
  174. package/dist/verify-core/index.js.map +1 -0
  175. package/dist/verify.d.ts +8 -0
  176. package/dist/verify.d.ts.map +1 -0
  177. package/dist/verify.js +8 -0
  178. package/dist/verify.js.map +1 -0
  179. package/openapi.json +4316 -1313
  180. package/package.json +121 -9
  181. package/src/account-core/index.ts +309 -0
  182. package/src/account.ts +11 -0
  183. package/src/angular/headless.ts +519 -0
  184. package/src/angular/index.ts +3 -0
  185. package/src/auth-links.ts +76 -0
  186. package/src/blog-core/index.ts +423 -0
  187. package/src/blog.ts +11 -0
  188. package/src/chat-core/index.ts +335 -0
  189. package/src/chat.ts +11 -0
  190. package/src/checkout-core/index.ts +225 -0
  191. package/src/checkout.ts +10 -0
  192. package/src/cli.ts +184 -28
  193. package/src/client.ts +998 -0
  194. package/src/contracts.ts +730 -11
  195. package/src/data-model-schema.ts +1 -1
  196. package/src/element.ts +102 -0
  197. package/src/embed-protocol.ts +100 -0
  198. package/src/framework-support.ts +440 -0
  199. package/src/legal-core/index.ts +276 -0
  200. package/src/marketing-core/index.ts +209 -0
  201. package/src/marketing.ts +7 -0
  202. package/src/mcp-adapters/index.ts +264 -0
  203. package/src/mcp-adapters.ts +7 -0
  204. package/src/model3d-core/index.ts +248 -0
  205. package/src/notifications-core/index.ts +650 -0
  206. package/src/portal-core/index.ts +1564 -0
  207. package/src/portal.ts +7 -0
  208. package/src/push-core/index.ts +335 -0
  209. package/src/qwik.tsx +602 -2
  210. package/src/react-marketing.tsx +5 -0
  211. package/src/react.tsx +434 -319
  212. package/src/seed-core/index.ts +735 -0
  213. package/src/seed.ts +7 -0
  214. package/src/seo-core/blog.ts +216 -0
  215. package/src/seo-core/commerce.ts +138 -0
  216. package/src/seo-core/index.ts +605 -0
  217. package/src/seo-core/local.ts +333 -0
  218. package/src/sitemap-core/index.ts +296 -0
  219. package/src/social-core/index.ts +103 -0
  220. package/src/social.ts +7 -0
  221. package/src/solid-compat.tsx +347 -0
  222. package/src/solid-surfaces.tsx +1311 -0
  223. package/src/solid.tsx +82 -60
  224. package/src/store-core/index.ts +426 -0
  225. package/src/store.ts +12 -0
  226. package/src/svelte/SocialLinks.svelte +84 -0
  227. package/src/svelte/headless.ts +435 -0
  228. package/src/svelte/index.ts +9 -0
  229. package/src/vanilla.ts +367 -0
  230. package/src/verify-core/index.ts +288 -0
  231. package/src/verify.ts +8 -0
  232. package/src/vue/headless.ts +527 -0
  233. package/src/vue/index.ts +3 -0
package/dist/index.cjs CHANGED
@@ -9724,12 +9724,31 @@ var chatbotFormDefinitionSchema = external_exports.object({
9724
9724
  description: external_exports.string(),
9725
9725
  fields: external_exports.array(chatbotFormFieldSchema),
9726
9726
  addsInquiry: external_exports.boolean(),
9727
- addsLead: external_exports.boolean()
9728
- });
9727
+ addsLead: external_exports.boolean(),
9728
+ /**
9729
+ * The RENDER contract — animation, multi-step + progress style, exit
9730
+ * confirmation, URL safety. The server has always sent this; the schema
9731
+ * dropped it, so anyone building a form UI on the typed client got a
9732
+ * bare field list and none of the behaviour the dashboard configured.
9733
+ */
9734
+ settings: external_exports.record(external_exports.unknown()).nullish(),
9735
+ /** Org avatar for the form header, when the form opts in. */
9736
+ orgIcon: external_exports.string().nullish(),
9737
+ /** Public action previews ("submitting adds you to the list"). */
9738
+ actions: external_exports.array(external_exports.record(external_exports.unknown())).nullish(),
9739
+ /** Non-sensitive business functions so `calculation` fields compute. */
9740
+ businessFunctions: external_exports.array(external_exports.record(external_exports.unknown())).nullish()
9741
+ }).passthrough();
9729
9742
  var chatbotFormSubmitInputSchema = external_exports.object({
9730
9743
  data: external_exports.record(external_exports.unknown()),
9731
9744
  submitterEmail: external_exports.string().email().optional(),
9732
9745
  submitterName: external_exports.string().optional(),
9746
+ /** Validate and run the full pipeline WITHOUT persisting. */
9747
+ dryRun: external_exports.boolean().optional(),
9748
+ /** Provenance the route accepts and this schema previously omitted. */
9749
+ source: external_exports.string().max(200).optional(),
9750
+ referrer: external_exports.string().max(500).optional(),
9751
+ metadata: external_exports.record(external_exports.unknown()).optional(),
9733
9752
  priorChat: external_exports.array(
9734
9753
  external_exports.object({
9735
9754
  role: external_exports.string().min(1).max(40),
@@ -9740,8 +9759,14 @@ var chatbotFormSubmitInputSchema = external_exports.object({
9740
9759
  });
9741
9760
  var chatbotFormSubmitResponseSchema = external_exports.object({
9742
9761
  success: external_exports.literal(true),
9743
- submissionId: external_exports.string(),
9744
- slug: external_exports.string()
9762
+ /**
9763
+ * NULL on a dry run — the submission validated but was deliberately not
9764
+ * persisted. Requiring a string here made every test submit throw.
9765
+ */
9766
+ submissionId: external_exports.string().nullable(),
9767
+ slug: external_exports.string(),
9768
+ /** True when nothing was written. Pairs with a null `submissionId`. */
9769
+ dryRun: external_exports.boolean().optional()
9745
9770
  });
9746
9771
  var chatbotPersistedSessionInputSchema = external_exports.object({
9747
9772
  visitorToken: external_exports.string().min(8).max(200),
@@ -10342,6 +10367,16 @@ var customerReturnRequestSchema = external_exports.object({
10342
10367
  * are separate enums and each is spelled as the database spells it.
10343
10368
  */
10344
10369
  status: openEnum("requested", "approved", "denied", "refunded", "cancelled"),
10370
+ /**
10371
+ * What was asked for: money back, or a replacement. Mirrors
10372
+ * `order_return_request_kind`. Rows created before this existed read
10373
+ * `refund`, which is what they were.
10374
+ */
10375
+ kind: openEnum("refund", "exchange"),
10376
+ /** On an exchange: the variant wanted instead, when one was chosen. */
10377
+ exchangeForVariantId: external_exports.string().nullable(),
10378
+ /** Set once a replacement ships — track it like any other shipment. */
10379
+ exchangeShipmentId: external_exports.string().nullable(),
10345
10380
  reason: external_exports.string().nullable(),
10346
10381
  items: external_exports.array(
10347
10382
  external_exports.object({
@@ -10383,6 +10418,16 @@ var customerOrderDetailSchema = external_exports.object({
10383
10418
  returnRequests: external_exports.array(customerReturnRequestSchema).optional()
10384
10419
  });
10385
10420
  var customerReturnRequestInputSchema = external_exports.object({
10421
+ /**
10422
+ * `refund` returns the money; `exchange` asks for a replacement. Defaults
10423
+ * to `refund`, so an omitted field means what it always meant.
10424
+ */
10425
+ kind: external_exports.enum(["refund", "exchange"]).optional(),
10426
+ /**
10427
+ * On an exchange, the variant wanted instead. Optional even then — "a
10428
+ * different size" is a real request that needs a conversation first.
10429
+ */
10430
+ exchangeForVariantId: external_exports.string().uuid().optional(),
10386
10431
  reason: external_exports.string().max(120).optional(),
10387
10432
  customerNote: external_exports.string().max(2e3).optional(),
10388
10433
  items: external_exports.array(
@@ -10396,6 +10441,262 @@ var customerReturnRequestCreatedSchema = external_exports.object({
10396
10441
  id: external_exports.string().nullable(),
10397
10442
  /** Mirrors the `order_return_request_status` pg enum. */
10398
10443
  status: openEnum("requested", "approved", "denied", "refunded", "cancelled"),
10444
+ /** Echoes back what was opened, so a UI need not assume. */
10445
+ kind: openEnum("refund", "exchange"),
10446
+ createdAt: external_exports.string().nullable()
10447
+ });
10448
+ var customerNotReceivedResultSchema = external_exports.object({
10449
+ id: external_exports.string(),
10450
+ /** True when a claim was already open; the original report is unchanged. */
10451
+ alreadyOpen: external_exports.boolean(),
10452
+ reportedAt: external_exports.string(),
10453
+ carrierStatus: openEnum(
10454
+ "pending",
10455
+ "label_created",
10456
+ "in_transit",
10457
+ "delivered",
10458
+ "returned"
10459
+ ),
10460
+ carrierDeliveredAt: external_exports.string().nullable(),
10461
+ contested: external_exports.boolean().optional()
10462
+ });
10463
+ var legalPresentationSchema = external_exports.object({
10464
+ /** Already resolved against the company logo — render as given. */
10465
+ logoUrl: external_exports.string().nullable(),
10466
+ showLogoInHeader: external_exports.boolean(),
10467
+ showLogoInFooter: external_exports.boolean(),
10468
+ headerHtml: external_exports.string().nullable(),
10469
+ footerHtml: external_exports.string().nullable()
10470
+ });
10471
+ var legalDocumentSummarySchema = external_exports.object({
10472
+ /** The URL path, without a leading slash: `privacy`, `terms`, … */
10473
+ slug: external_exports.string(),
10474
+ title: external_exports.string(),
10475
+ version: external_exports.number(),
10476
+ /** ISO 8601. Render as "Last updated". */
10477
+ effectiveDate: external_exports.string().nullable(),
10478
+ showInFooter: external_exports.boolean(),
10479
+ updatedAt: external_exports.string()
10480
+ });
10481
+ var legalListResponseSchema = external_exports.object({
10482
+ items: external_exports.array(legalDocumentSummarySchema),
10483
+ presentation: legalPresentationSchema
10484
+ });
10485
+ var legalDocumentSchema = legalDocumentSummarySchema.extend({
10486
+ /** Sanitised server-side on write, so this is safe to render as HTML. */
10487
+ contentHtml: external_exports.string(),
10488
+ presentation: legalPresentationSchema
10489
+ });
10490
+ var customerPushDeviceSchema = external_exports.object({
10491
+ id: external_exports.string(),
10492
+ endpoint: external_exports.string(),
10493
+ userAgent: external_exports.string().nullable(),
10494
+ label: external_exports.string().nullable(),
10495
+ /** Null = every category. `[]` = none, but the device stays registered. */
10496
+ categories: external_exports.array(external_exports.string()).nullable(),
10497
+ lastSeenAt: external_exports.string().nullable(),
10498
+ createdAt: external_exports.string()
10499
+ });
10500
+ var customerPushConfigSchema = external_exports.object({
10501
+ vapidPublicKey: external_exports.string().nullable(),
10502
+ enabled: external_exports.boolean(),
10503
+ devices: external_exports.array(customerPushDeviceSchema)
10504
+ });
10505
+ var customerInviteResendResponseSchema = external_exports.object({
10506
+ id: external_exports.string(),
10507
+ /** The NEW link. The previous one no longer works. */
10508
+ url: external_exports.string(),
10509
+ expiresAt: external_exports.string().nullable(),
10510
+ /** Includes this send, so a list can show "sent 3 times". */
10511
+ sendCount: external_exports.number()
10512
+ });
10513
+ var schedulingEventTypeSchema = external_exports.object({
10514
+ id: external_exports.string(),
10515
+ name: external_exports.string(),
10516
+ slug: external_exports.string(),
10517
+ description: external_exports.string().nullable(),
10518
+ durationMinutes: external_exports.number(),
10519
+ locationType: external_exports.string(),
10520
+ /** google_meet | zoom | teams | null when the meeting is in person. */
10521
+ meetingProvider: external_exports.string().nullable(),
10522
+ color: external_exports.string().nullable(),
10523
+ /** When true a booking lands `pending`, not `confirmed`. */
10524
+ requiresApproval: external_exports.boolean()
10525
+ });
10526
+ var schedulingQuestionSchema = external_exports.object({
10527
+ id: external_exports.string(),
10528
+ label: external_exports.string()
10529
+ }).passthrough();
10530
+ var schedulingEventTypeListSchema = external_exports.object({
10531
+ eventTypes: external_exports.array(schedulingEventTypeSchema)
10532
+ });
10533
+ var schedulingEventTypeDetailSchema = external_exports.object({
10534
+ eventType: schedulingEventTypeSchema,
10535
+ questions: external_exports.array(schedulingQuestionSchema)
10536
+ });
10537
+ var schedulingSlotSchema = external_exports.object({
10538
+ startAt: external_exports.string(),
10539
+ endAt: external_exports.string()
10540
+ });
10541
+ var schedulingSlotsResponseSchema = external_exports.object({
10542
+ slots: external_exports.array(schedulingSlotSchema)
10543
+ });
10544
+ var schedulingBookingStatusSchema = openEnum(
10545
+ "pending",
10546
+ "confirmed",
10547
+ "canceled",
10548
+ "rescheduled"
10549
+ );
10550
+ var schedulingBookingViewSchema = external_exports.object({
10551
+ booking: external_exports.object({
10552
+ id: external_exports.string(),
10553
+ startAt: external_exports.string(),
10554
+ endAt: external_exports.string(),
10555
+ status: schedulingBookingStatusSchema,
10556
+ title: external_exports.string(),
10557
+ notes: external_exports.string().nullable(),
10558
+ /** The conference URL, once there is one. */
10559
+ conferenceLink: external_exports.string().nullable()
10560
+ }),
10561
+ invitee: external_exports.object({ name: external_exports.string(), email: external_exports.string(), timezone: external_exports.string() }).nullable()
10562
+ });
10563
+ var schedulingBookingResultSchema = external_exports.object({
10564
+ bookingId: external_exports.string(),
10565
+ status: schedulingBookingStatusSchema,
10566
+ /**
10567
+ * Three separate signed tokens, deliberately.
10568
+ *
10569
+ * A cancel link in an email must not also be able to reschedule, and
10570
+ * neither should read the whole booking. Handing out one token for all
10571
+ * three would make every emailed link as powerful as the strongest
10572
+ * action it enables.
10573
+ */
10574
+ manageToken: external_exports.string(),
10575
+ rescheduleToken: external_exports.string(),
10576
+ cancelToken: external_exports.string()
10577
+ }).passthrough();
10578
+ var schedulingRescheduleResultSchema = external_exports.object({
10579
+ bookingId: external_exports.string(),
10580
+ startAt: external_exports.string(),
10581
+ endAt: external_exports.string(),
10582
+ /** Re-minted on reschedule — read it back rather than reusing the old one. */
10583
+ conferenceLink: external_exports.string().nullable().optional()
10584
+ }).passthrough();
10585
+ var schedulingCancelResultSchema = external_exports.object({ ok: external_exports.boolean() }).passthrough();
10586
+ var customerSubscriptionOfferingSchema = external_exports.object({
10587
+ id: external_exports.string(),
10588
+ name: external_exports.string(),
10589
+ description: external_exports.string().nullable(),
10590
+ imageUrl: external_exports.string().nullable(),
10591
+ amountCents: external_exports.number(),
10592
+ interval: external_exports.string()
10593
+ });
10594
+ var customerSubscriptionSchema = external_exports.object({
10595
+ /** active | expired | cancelled | pending | failed */
10596
+ status: openEnum("active", "expired", "cancelled", "pending", "failed"),
10597
+ /** trial | monthly_subscribed | annual_subscribed | lifetime */
10598
+ type: openEnum(
10599
+ "trial",
10600
+ "monthly_subscribed",
10601
+ "annual_subscribed",
10602
+ "lifetime"
10603
+ ).nullable(),
10604
+ /**
10605
+ * The entitlement decision, computed server-side by the same function the
10606
+ * content gates use.
10607
+ *
10608
+ * **Render from this, not from `status`.** Two cases break a naive
10609
+ * `status === "active"` check: a lifetime purchase has no period to expire,
10610
+ * and a cancelled subscription keeps access until the period already paid
10611
+ * for runs out.
10612
+ */
10613
+ hasAccess: external_exports.boolean(),
10614
+ /**
10615
+ * Cancelled, but the paid period has not ended. The honest label is
10616
+ * "active until {expiresAt}" — not "cancelled".
10617
+ */
10618
+ cancelledButActive: external_exports.boolean(),
10619
+ startedAt: external_exports.string().nullable(),
10620
+ /** End of the paid period. Null for lifetime. */
10621
+ expiresAt: external_exports.string().nullable(),
10622
+ cancelledAt: external_exports.string().nullable(),
10623
+ renewedAt: external_exports.string().nullable(),
10624
+ trialEndsAt: external_exports.string().nullable(),
10625
+ trialUsed: external_exports.boolean(),
10626
+ provider: external_exports.string().nullable(),
10627
+ /** The offering they are on, when it still exists. */
10628
+ plan: customerSubscriptionOfferingSchema.nullable(),
10629
+ /** Null means the plan includes no service calls at all. */
10630
+ includedServiceCallsPerPeriod: external_exports.number().nullable(),
10631
+ serviceCallsUsedInPeriod: external_exports.number(),
10632
+ periodStartedAt: external_exports.string().nullable()
10633
+ });
10634
+ var customerSubscriptionResponseSchema = external_exports.object({
10635
+ /** Null when this customer has never subscribed to this org. */
10636
+ subscription: customerSubscriptionSchema.nullable(),
10637
+ /** The org's live offerings, cheapest first. */
10638
+ offerings: external_exports.array(customerSubscriptionOfferingSchema)
10639
+ });
10640
+ var customerSubscriptionCancelResponseSchema = external_exports.object({
10641
+ /** True when a cancellation is now pending at the end of the period. */
10642
+ cancelAtPeriodEnd: external_exports.boolean(),
10643
+ resumed: external_exports.boolean(),
10644
+ /**
10645
+ * Access continues until this moment. Say "active until {this}", because
10646
+ * that is what is true — cancelling ends the renewal, not the access.
10647
+ */
10648
+ accessUntil: external_exports.string().nullable(),
10649
+ /**
10650
+ * The stored status still reads its old value until the provider's webhook
10651
+ * lands. Render from `cancelAtPeriodEnd`, not from a re-read.
10652
+ */
10653
+ statusPending: external_exports.boolean()
10654
+ });
10655
+ var customerSubscriberContentItemSchema = external_exports.object({
10656
+ id: external_exports.string(),
10657
+ slug: external_exports.string(),
10658
+ title: external_exports.string(),
10659
+ /** The pitch. Travels even when locked — the BODY never does. */
10660
+ excerpt: external_exports.string().nullable(),
10661
+ featuredImageUrl: external_exports.string().nullable(),
10662
+ publishedAt: external_exports.string().nullable(),
10663
+ tags: external_exports.array(external_exports.string()),
10664
+ accessLevel: external_exports.string(),
10665
+ downloadAccessLevel: external_exports.string(),
10666
+ /** False when the post is readable but its downloads are not. */
10667
+ downloadsAvailable: external_exports.boolean()
10668
+ });
10669
+ var customerSubscriberContentResponseSchema = external_exports.object({
10670
+ items: external_exports.array(customerSubscriberContentItemSchema),
10671
+ /**
10672
+ * False means these are LOCKED previews, not an empty entitlement. Show
10673
+ * them with the offer — an empty list would hide the pitch at exactly the
10674
+ * moment it is most relevant.
10675
+ */
10676
+ entitled: external_exports.boolean()
10677
+ });
10678
+ var customerProductReviewSchema = external_exports.object({
10679
+ id: external_exports.string(),
10680
+ productId: external_exports.string(),
10681
+ productName: external_exports.string(),
10682
+ rating: external_exports.number(),
10683
+ content: external_exports.string(),
10684
+ /**
10685
+ * False means QUEUED for the org to approve, not rejected. Surface it as
10686
+ * "awaiting review" — a customer who thinks their review vanished writes it
10687
+ * again, or writes to support.
10688
+ */
10689
+ isApproved: external_exports.boolean(),
10690
+ createdAt: external_exports.string()
10691
+ });
10692
+ var customerProductReviewListSchema = external_exports.object({
10693
+ items: external_exports.array(customerProductReviewSchema)
10694
+ });
10695
+ var customerProductReviewCreatedSchema = external_exports.object({
10696
+ id: external_exports.string().nullable(),
10697
+ isApproved: external_exports.boolean(),
10698
+ /** The inverse of `isApproved`, named for what the UI should say. */
10699
+ awaitingModeration: external_exports.boolean(),
10399
10700
  createdAt: external_exports.string().nullable()
10400
10701
  });
10401
10702
  var customerDownloadSchema = external_exports.object({
@@ -10439,6 +10740,75 @@ var siteBrandingSchema = external_exports.object({
10439
10740
  orgName: external_exports.string().nullable(),
10440
10741
  orgIcon: external_exports.string().nullable()
10441
10742
  });
10743
+ var customerInvoiceListResponseSchema = external_exports.object({
10744
+ items: external_exports.array(customerInvoiceSummarySchema)
10745
+ });
10746
+ var customerQuoteListResponseSchema = external_exports.object({
10747
+ items: external_exports.array(customerQuoteSummarySchema)
10748
+ });
10749
+ var customerContractListResponseSchema = external_exports.object({
10750
+ items: external_exports.array(customerContractSummarySchema)
10751
+ });
10752
+ var customerShipmentSummarySchema = external_exports.object({
10753
+ id: external_exports.string(),
10754
+ orderId: external_exports.string(),
10755
+ orderNumber: external_exports.string().nullable(),
10756
+ carrier: external_exports.string().nullable(),
10757
+ trackingNumber: external_exports.string().nullable(),
10758
+ trackingUrl: external_exports.string().nullable(),
10759
+ serviceName: external_exports.string().nullable(),
10760
+ status: external_exports.string(),
10761
+ /** A date STRING, not a timestamp — the column is text. */
10762
+ estimatedDelivery: external_exports.string().nullable(),
10763
+ shippedAt: external_exports.string().nullable(),
10764
+ deliveredAt: external_exports.string().nullable()
10765
+ });
10766
+ var customerShipmentListResponseSchema = external_exports.object({
10767
+ items: external_exports.array(customerShipmentSummarySchema)
10768
+ });
10769
+ var customerPortalMessageSchema = external_exports.object({
10770
+ id: external_exports.string(),
10771
+ /** `inbound` = the customer wrote it; `outbound` = staff did. */
10772
+ direction: openEnum("inbound", "outbound"),
10773
+ channel: openEnum("portal", "email", "sms"),
10774
+ authorName: external_exports.string().nullable(),
10775
+ body: external_exports.string(),
10776
+ attachment: external_exports.object({
10777
+ url: external_exports.string(),
10778
+ name: external_exports.string(),
10779
+ mimeType: external_exports.string(),
10780
+ sizeBytes: external_exports.number()
10781
+ }).nullable(),
10782
+ jobId: external_exports.string().nullable(),
10783
+ readByCustomerAt: external_exports.string().nullable(),
10784
+ createdAt: external_exports.string()
10785
+ });
10786
+ var customerPortalMessageListResponseSchema = external_exports.object({
10787
+ items: external_exports.array(customerPortalMessageSchema)
10788
+ });
10789
+ var customerPortalMessagePostInputSchema = external_exports.object({
10790
+ body: external_exports.string().min(1).max(4e3),
10791
+ /** Thread the message under a specific job. */
10792
+ jobId: external_exports.string().uuid().optional()
10793
+ });
10794
+ var customerPortalMessagesMarkReadResponseSchema = external_exports.object({
10795
+ marked: external_exports.number()
10796
+ });
10797
+ var customerReturnRequestStatusSchema = external_exports.object({
10798
+ id: external_exports.string(),
10799
+ /** Mirrors the `order_return_request_status` pg enum. */
10800
+ status: openEnum("requested", "approved", "denied", "refunded", "cancelled"),
10801
+ reason: external_exports.string().nullable(),
10802
+ customerNote: external_exports.string().nullable(),
10803
+ /** Staff's answer. The whole point when a return is denied. */
10804
+ resolutionNote: external_exports.string().nullable(),
10805
+ items: external_exports.array(external_exports.record(external_exports.string(), external_exports.unknown())).nullable(),
10806
+ resolvedAt: external_exports.string().nullable(),
10807
+ createdAt: external_exports.string()
10808
+ });
10809
+ var customerReturnRequestListResponseSchema = external_exports.object({
10810
+ items: external_exports.array(customerReturnRequestStatusSchema)
10811
+ });
10442
10812
  var customerReviewSummarySchema = external_exports.object({
10443
10813
  id: external_exports.string(),
10444
10814
  rating: external_exports.number().int(),
@@ -10489,7 +10859,19 @@ var customerContactCompanyResponseSchema = external_exports.object({
10489
10859
  var customerJobEtaAssignmentSchema = external_exports.object({
10490
10860
  displayName: external_exports.string(),
10491
10861
  role: external_exports.string().nullable(),
10492
- dispatchStatus: external_exports.string(),
10862
+ /**
10863
+ * This technician's own stage. `openEnum` because the column is TEXT and
10864
+ * an org's board can grow a value before the SDK knows about it — an
10865
+ * unknown status should render as itself, not break the response.
10866
+ */
10867
+ dispatchStatus: openEnum(
10868
+ "pending",
10869
+ "en_route",
10870
+ "on_site",
10871
+ "in_progress",
10872
+ "completed",
10873
+ "declined"
10874
+ ),
10493
10875
  lastKnownLocation: external_exports.object({
10494
10876
  lat: external_exports.number(),
10495
10877
  lng: external_exports.number(),
@@ -10497,6 +10879,35 @@ var customerJobEtaAssignmentSchema = external_exports.object({
10497
10879
  }).nullable()
10498
10880
  });
10499
10881
  var customerJobEtaResponseSchema = external_exports.object({
10882
+ /**
10883
+ * Where the JOB is — promoted from the assignees by the dispatch board,
10884
+ * NOT the same as any one technician's status.
10885
+ *
10886
+ * The promotion rules are why this is returned rather than left to the
10887
+ * consumer: `en_route`/`arrived`/`started` land on the FIRST assignee to
10888
+ * reach them, while `completed` waits for the LAST. Aggregating that
10889
+ * client-side gets it wrong in the direction that tells a customer the work
10890
+ * is finished when one of three techs has packed up.
10891
+ */
10892
+ dispatchStatus: openEnum(
10893
+ "unscheduled",
10894
+ "scheduled",
10895
+ "en_route",
10896
+ "arrived",
10897
+ "started",
10898
+ "completed"
10899
+ ),
10900
+ /**
10901
+ * When each stage happened. A customer reading "en route" wants to know
10902
+ * since when — a status with no timestamp is why people phone to ask.
10903
+ */
10904
+ timeline: external_exports.object({
10905
+ scheduledStartAt: external_exports.string().nullable(),
10906
+ enRouteAt: external_exports.string().nullable(),
10907
+ arrivedAt: external_exports.string().nullable(),
10908
+ startedAt: external_exports.string().nullable(),
10909
+ completedAt: external_exports.string().nullable()
10910
+ }),
10500
10911
  assignments: external_exports.array(customerJobEtaAssignmentSchema),
10501
10912
  eta: external_exports.object({
10502
10913
  seconds: external_exports.number().nullable(),
@@ -10636,12 +11047,83 @@ var storefrontProductRowSchema = external_exports.object({
10636
11047
  /** Resolved category (name/description), when the product is categorized. */
10637
11048
  category: storefrontProductCategorySchema.nullable().optional(),
10638
11049
  images: external_exports.array(external_exports.string()).nullable().optional(),
11050
+ /**
11051
+ * Web-renderable 3D model — `.glb`, `.gltf`, `.obj` or `.stl`.
11052
+ *
11053
+ * All four fields below are ABSENT (not null) unless the org has the
11054
+ * `ecommerce.product_3d` add-on. Absence is the normal case: most
11055
+ * businesses do not sell anything with a model. Use
11056
+ * `@businessdash/sdk/model3d` to turn these into something renderable.
11057
+ */
11058
+ model3dUrl: external_exports.string().nullable().optional(),
11059
+ /** Apple AR Quick Look companion, `.usdz`. iOS/iPadOS/visionOS Safari. */
11060
+ model3dUsdzUrl: external_exports.string().nullable().optional(),
11061
+ /**
11062
+ * True when the org attached a CAD file (`.step`/`.iges`/native).
11063
+ *
11064
+ * The URL itself is deliberately NOT here. CAD files are the largest
11065
+ * thing the platform serves and are the org's intellectual property, so
11066
+ * they are issued by `GET storefront/products/{id}/cad`, which requires
11067
+ * cookies, rate-limits the caller and re-checks the entitlement.
11068
+ * Publishing the raw URL in a payload any visitor can fetch would route
11069
+ * around all three.
11070
+ */
11071
+ model3dCadAvailable: external_exports.boolean().optional(),
11072
+ /** Filename for the download link — "bracket-v3.step". */
11073
+ model3dCadName: external_exports.string().nullable().optional(),
10639
11074
  createdAt: external_exports.string()
10640
11075
  }).passthrough();
10641
11076
  var storefrontListProductsResponseSchema = external_exports.object({
10642
11077
  items: external_exports.array(storefrontProductRowSchema),
10643
11078
  nextCursor: external_exports.number().nullable()
10644
11079
  });
11080
+ var couponSchema = external_exports.object({
11081
+ id: external_exports.string(),
11082
+ code: external_exports.string(),
11083
+ discountType: external_exports.string(),
11084
+ value: external_exports.number(),
11085
+ isActive: external_exports.boolean(),
11086
+ maxUses: external_exports.number().nullable(),
11087
+ usedCount: external_exports.number(),
11088
+ validUntil: external_exports.string().nullable(),
11089
+ stripeCouponId: external_exports.string().nullable(),
11090
+ stripePromotionCodeId: external_exports.string().nullable()
11091
+ });
11092
+ var couponCreateInputSchema = external_exports.object({
11093
+ code: external_exports.string().min(3).max(64),
11094
+ discountType: external_exports.enum(["percent", "amount"]),
11095
+ value: external_exports.number().positive(),
11096
+ validFrom: external_exports.coerce.date().optional(),
11097
+ validUntil: external_exports.coerce.date().nullish(),
11098
+ maxUses: external_exports.number().int().positive().nullish(),
11099
+ isActive: external_exports.boolean().optional(),
11100
+ duration: external_exports.enum(["once", "forever", "repeating"]).optional(),
11101
+ durationInMonths: external_exports.number().int().positive().nullish(),
11102
+ appliesTo: external_exports.enum(["order", "shipping", "both"]).optional()
11103
+ });
11104
+ var couponCreateResponseSchema = external_exports.object({
11105
+ coupon: couponSchema,
11106
+ stripeSynced: external_exports.boolean(),
11107
+ stripeError: external_exports.string().nullable()
11108
+ });
11109
+ var couponListResponseSchema = external_exports.object({
11110
+ coupons: external_exports.array(couponSchema)
11111
+ });
11112
+ var storefrontSyncToStripeResponseSchema = external_exports.object({
11113
+ synced: external_exports.array(
11114
+ external_exports.object({
11115
+ productId: external_exports.string(),
11116
+ stripeProductId: external_exports.string(),
11117
+ /** Variant combinations that got a Stripe Price. */
11118
+ combinationsSynced: external_exports.number()
11119
+ })
11120
+ ),
11121
+ failed: external_exports.array(external_exports.object({ productId: external_exports.string(), error: external_exports.string() })),
11122
+ /** Products still unsynced after this call — keep calling until 0. */
11123
+ remaining: external_exports.number(),
11124
+ /** Connected account written to; null means the platform account. */
11125
+ connectedAccountId: external_exports.string().nullable()
11126
+ });
10645
11127
  var storefrontProductDetailSchema = storefrontProductRowSchema.and(
10646
11128
  external_exports.object({
10647
11129
  variants: external_exports.array(external_exports.record(external_exports.string(), external_exports.unknown())),
@@ -11163,6 +11645,8 @@ var bundleCompanySchema = external_exports.object({
11163
11645
  });
11164
11646
  var bundleGalleryItemSchema = external_exports.object({
11165
11647
  id: external_exports.string(),
11648
+ /** Sent by the server on every item and dropped here until now. */
11649
+ description: external_exports.string().nullish(),
11166
11650
  type: external_exports.enum(["image", "video"]),
11167
11651
  src: external_exports.string(),
11168
11652
  width: external_exports.number().nullable(),
@@ -11778,6 +12262,10 @@ var BiabDevClient = class {
11778
12262
  get shipping() {
11779
12263
  return new BiabDevShippingClient(this);
11780
12264
  }
12265
+ /** Customer-portal invitations — currently resend. */
12266
+ get customerInvites() {
12267
+ return new BiabDevCustomerInvitesClient(this);
12268
+ }
11781
12269
  get notifications() {
11782
12270
  return new BiabDevNotificationsClient(this);
11783
12271
  }
@@ -11794,6 +12282,16 @@ var BiabDevClient = class {
11794
12282
  get hiring() {
11795
12283
  return new BiabDevHiringClient(this);
11796
12284
  }
12285
+ /**
12286
+ * The org's published legal pages — privacy, terms, refund policy, whatever
12287
+ * they authored in the dashboard.
12288
+ *
12289
+ * Pair with `@businessdash/sdk/legal` to render them without writing a page
12290
+ * per document.
12291
+ */
12292
+ get legal() {
12293
+ return new BiabDevLegalClient(this);
12294
+ }
11797
12295
  get chatbot() {
11798
12296
  return new BiabDevChatbotClient(this);
11799
12297
  }
@@ -11861,6 +12359,7 @@ var BiabDevSiteClient = class {
11861
12359
  this.client = client;
11862
12360
  this.siteId = siteId;
11863
12361
  this.collections = new BiabDevCollectionsClient(client, siteId);
12362
+ this.scheduling = new BiabDevSchedulingClient(client, siteId);
11864
12363
  this.rows = new BiabDevRowsClient(client, siteId);
11865
12364
  this.dataModel = new BiabDevDataModelClient(client, siteId);
11866
12365
  this.analytics = new BiabDevAnalyticsClient(client, siteId);
@@ -11905,6 +12404,14 @@ var BiabDevSiteClient = class {
11905
12404
  */
11906
12405
  marketing;
11907
12406
  parallelPages;
12407
+ /**
12408
+ * Booking and conference calls.
12409
+ *
12410
+ * Previously reachable only through `sdk.ts`'s separate scheduling
12411
+ * resource, which is why the OpenAPI generator — which reads this file —
12412
+ * never saw it, and why no non-JS starter had scheduling at all.
12413
+ */
12414
+ scheduling;
11908
12415
  /**
11909
12416
  * The org's storefront branding — logo + favicon (site static media) plus
11910
12417
  * the org name + icon. Render the masthead/favicon/og without the org
@@ -11916,6 +12423,27 @@ var BiabDevSiteClient = class {
11916
12423
  * <img src={b.logoUrl ?? b.orgIcon ?? ""} alt={b.orgName ?? ""} />
11917
12424
  * ```
11918
12425
  */
12426
+ /**
12427
+ * Every URL the PLATFORM owns the shape of, as JSON.
12428
+ *
12429
+ * Published site-builder pages, published legal documents, and every
12430
+ * materialised programmatic-page URL. Blog posts and products are not here
12431
+ * — the platform does not know where your site renders them. Merge those in
12432
+ * with `@businessdash/sdk/sitemap`, which handles the whole job.
12433
+ *
12434
+ * Paths are relative, so you join them against your own origin rather than
12435
+ * the org's primary verified domain.
12436
+ */
12437
+ async sitemapEntries() {
12438
+ return this.client.request({
12439
+ path: `sites/${encodeURIComponent(this.siteId)}/sitemap-entries`,
12440
+ responseSchema: external_exports.object({
12441
+ entries: external_exports.array(
12442
+ external_exports.object({ loc: external_exports.string(), lastmod: external_exports.string().optional() })
12443
+ )
12444
+ })
12445
+ });
12446
+ }
11919
12447
  async branding() {
11920
12448
  return this.client.request({
11921
12449
  path: `sites/${encodeURIComponent(this.siteId)}/branding`,
@@ -12548,6 +13076,42 @@ var BiabDevStorefrontClient = class {
12548
13076
  responseSchema: storefrontSessionResponseSchema
12549
13077
  });
12550
13078
  }
13079
+ /**
13080
+ * Push your catalog into YOUR OWN Stripe account.
13081
+ *
13082
+ * Products and their variant combinations become Stripe Products and
13083
+ * Prices on the Stripe account connected to your workspace, so you can
13084
+ * manage the catalog here and let Stripe be the system of record for
13085
+ * money. Safe to re-run: an unchanged product is left alone, and a new
13086
+ * Price is minted only when the amount actually changed (Stripe Prices
13087
+ * are immutable on amount).
13088
+ *
13089
+ * Requires a SECRET key holding `storefront:write` — never a publishable
13090
+ * token, because this spends against Stripe on your behalf.
13091
+ *
13092
+ * Pass `productId` to sync one product. Omit it to sync everything not yet
13093
+ * pushed, in bounded batches: check `remaining` and call again until it
13094
+ * reaches 0.
13095
+ *
13096
+ * ```ts
13097
+ * let remaining = 1;
13098
+ * while (remaining > 0) {
13099
+ * const res = await biab.storefront.syncToStripe();
13100
+ * remaining = res.remaining;
13101
+ * }
13102
+ * ```
13103
+ *
13104
+ * Per-product failures are returned in `failed` rather than throwing, so
13105
+ * one bad product doesn't abandon the batch.
13106
+ */
13107
+ async syncToStripe(input) {
13108
+ return this.client.request({
13109
+ method: "POST",
13110
+ path: "storefront/products/sync-to-stripe",
13111
+ body: input?.productId ? { productId: input.productId } : {},
13112
+ responseSchema: storefrontSyncToStripeResponseSchema
13113
+ });
13114
+ }
12551
13115
  /**
12552
13116
  * Paginated list of live products for the calling org's storefront.
12553
13117
  * Cursor is an opaque integer offset — pass back the response's
@@ -12602,6 +13166,38 @@ var BiabDevStorefrontClient = class {
12602
13166
  * via `BiabApiError` if the product isn't live or doesn't belong
12603
13167
  * to the org bound to the API key.
12604
13168
  */
13169
+ /**
13170
+ * The CAD file for a product — STEP, IGES, or a native part file.
13171
+ *
13172
+ * ## Call this from YOUR server, then proxy it
13173
+ *
13174
+ * The API key is a server secret, so a browser cannot reach this directly.
13175
+ * Expose your own route (`/api/products/:id/cad`), call this behind it, and
13176
+ * redirect the visitor to the URL it returns.
13177
+ *
13178
+ * The platform withholds the raw URL from every product payload on purpose:
13179
+ * CAD files are the largest thing it serves and are the org's intellectual
13180
+ * property, so a catalog of naked URLs is a design library published to
13181
+ * anyone willing to write a loop. This endpoint requires a `biab_cad` cookie
13182
+ * on the incoming request, rate-limits per IP, and re-checks the
13183
+ * `ecommerce.product_3d` entitlement before answering.
13184
+ *
13185
+ * `cacheSeconds` is what to put on your own response — CAD at a content URL
13186
+ * does not change, so caching hard is where the bandwidth saving comes from.
13187
+ *
13188
+ * Rejects 404 when the product is a draft, has no CAD file, or the org lacks
13189
+ * the add-on. Those are deliberately one answer.
13190
+ */
13191
+ async getCadDownload(productId) {
13192
+ return this.client.request({
13193
+ path: `storefront/products/${encodeURIComponent(productId)}/cad`,
13194
+ responseSchema: external_exports.object({
13195
+ url: external_exports.string(),
13196
+ fileName: external_exports.string().nullable(),
13197
+ cacheSeconds: external_exports.number()
13198
+ })
13199
+ });
13200
+ }
12605
13201
  async getProduct(productId) {
12606
13202
  return this.client.request({
12607
13203
  path: `storefront/products/${encodeURIComponent(productId)}`,
@@ -12942,6 +13538,47 @@ var BiabDevCouponsClient = class {
12942
13538
  * else toast.error(result.message);
12943
13539
  * ```
12944
13540
  */
13541
+ /**
13542
+ * Create a coupon and make it live in YOUR OWN Stripe account in one call —
13543
+ * a Stripe Coupon plus a Promotion Code, so the same string works on your
13544
+ * storefront and on Stripe-hosted Checkout.
13545
+ *
13546
+ * Creation and the Stripe sync are one operation deliberately: a coupon
13547
+ * that exists locally but not in Stripe is the failure worth designing out,
13548
+ * where a customer types a code your storefront accepts and Stripe rejects.
13549
+ * If the sync fails the coupon is still created and `stripeSynced` comes
13550
+ * back `false` with the reason, rather than pretending it is live.
13551
+ *
13552
+ * Requires a SECRET key holding `storefront:write`.
13553
+ *
13554
+ * ```ts
13555
+ * const { coupon, stripeSynced } = await biab.coupons.create({
13556
+ * code: 'WELCOME10',
13557
+ * discountType: 'percent',
13558
+ * value: 10,
13559
+ * })
13560
+ * ```
13561
+ *
13562
+ * Buy-X-get-Y and bundle-gift coupons aren't available here — Stripe has no
13563
+ * native BXGY, so those run through our own cart math and need the offer
13564
+ * rows the dashboard collects.
13565
+ */
13566
+ async create(input) {
13567
+ const body = couponCreateInputSchema.parse(input);
13568
+ return this.client.request({
13569
+ method: "POST",
13570
+ path: "coupons",
13571
+ body,
13572
+ responseSchema: couponCreateResponseSchema
13573
+ });
13574
+ }
13575
+ /** Every coupon on the workspace, newest first. Requires `storefront:write`. */
13576
+ async list() {
13577
+ return this.client.request({
13578
+ path: "coupons",
13579
+ responseSchema: couponListResponseSchema
13580
+ });
13581
+ }
12945
13582
  async validate(code) {
12946
13583
  const body = couponValidateInputSchema.parse({ code });
12947
13584
  return this.client.request({
@@ -13288,6 +13925,38 @@ var BiabDevHiringClient = class {
13288
13925
  });
13289
13926
  }
13290
13927
  };
13928
+ var BiabDevLegalClient = class {
13929
+ constructor(client) {
13930
+ this.client = client;
13931
+ }
13932
+ client;
13933
+ /**
13934
+ * Every published document, plus the header/footer presentation.
13935
+ *
13936
+ * Both in one response because the common use — a footer link list — needs
13937
+ * the titles and the presentation together, and a second round trip for the
13938
+ * latter is one a site either makes on every page or skips entirely.
13939
+ */
13940
+ async list() {
13941
+ return this.client.request({
13942
+ path: "legal",
13943
+ responseSchema: legalListResponseSchema
13944
+ });
13945
+ }
13946
+ /**
13947
+ * One document by slug, body included.
13948
+ *
13949
+ * Rejects with a 404 when the slug is unpublished or absent — the two are
13950
+ * deliberately indistinguishable, since "exists but hidden" would leak that
13951
+ * an org is drafting a policy and is not something a caller can act on.
13952
+ */
13953
+ async get(slug) {
13954
+ return this.client.request({
13955
+ path: `legal/${encodeURIComponent(slug)}`,
13956
+ responseSchema: legalDocumentSchema
13957
+ });
13958
+ }
13959
+ };
13291
13960
  var BiabDevChatbotClient = class {
13292
13961
  constructor(client) {
13293
13962
  this.client = client;
@@ -13854,6 +14523,129 @@ var BiabDevCustomerPortalClient = class _BiabDevCustomerPortalClient {
13854
14523
  headers: this.headers()
13855
14524
  });
13856
14525
  }
14526
+ /**
14527
+ * The return requests on one order, newest first.
14528
+ *
14529
+ * `resolutionNote` carries staff's answer — when a return is denied that IS
14530
+ * the answer, and hiding it just moves the question to email.
14531
+ */
14532
+ async listReturnRequests(orderId) {
14533
+ return this.client.request({
14534
+ path: `customer-portal/orders/${encodeURIComponent(orderId)}/return-request`,
14535
+ responseSchema: customerReturnRequestListResponseSchema,
14536
+ headers: this.headers()
14537
+ });
14538
+ }
14539
+ /**
14540
+ * The customer's message thread with the org's staff, newest first.
14541
+ *
14542
+ * Automated rows — the review-ask and similar — are excluded server-side, so
14543
+ * this is only what a person wrote.
14544
+ */
14545
+ async listMessages(opts) {
14546
+ const params = new URLSearchParams();
14547
+ if (typeof opts?.limit === "number")
14548
+ params.set("limit", String(opts.limit));
14549
+ if (opts?.jobId) params.set("jobId", opts.jobId);
14550
+ const qs = params.toString();
14551
+ return this.client.request({
14552
+ path: `customer-portal/messages${qs ? `?${qs}` : ""}`,
14553
+ responseSchema: customerPortalMessageListResponseSchema,
14554
+ headers: this.headers()
14555
+ });
14556
+ }
14557
+ /** Send a message to the org's staff. Lands in the CRM timeline. */
14558
+ async postMessage(input) {
14559
+ return this.client.request({
14560
+ path: "customer-portal/messages",
14561
+ method: "POST",
14562
+ body: input,
14563
+ responseSchema: customerPortalMessageSchema,
14564
+ headers: this.headers()
14565
+ });
14566
+ }
14567
+ /**
14568
+ * Mark the staff messages read up to now.
14569
+ *
14570
+ * One-way: it never clears a stamp. A portal that could un-read a message
14571
+ * would let a customer hide from staff that they had seen something.
14572
+ */
14573
+ async markMessagesRead() {
14574
+ return this.client.request({
14575
+ path: "customer-portal/messages",
14576
+ method: "PATCH",
14577
+ responseSchema: customerPortalMessagesMarkReadResponseSchema,
14578
+ headers: this.headers()
14579
+ });
14580
+ }
14581
+ /**
14582
+ * The customer's invoices, newest first.
14583
+ *
14584
+ * `unpaid: true` filters on the computed BALANCE rather than on the status
14585
+ * string, because a partially-paid invoice still owes money whatever it is
14586
+ * called. This is the call behind "show me everything I owe" — which had no
14587
+ * endpoint at all before 0.9.61.
14588
+ */
14589
+ async listInvoices(opts) {
14590
+ const params = new URLSearchParams();
14591
+ if (typeof opts?.limit === "number")
14592
+ params.set("limit", String(opts.limit));
14593
+ if (opts?.status) params.set("status", opts.status);
14594
+ if (opts?.unpaid) params.set("unpaid", "1");
14595
+ const qs = params.toString();
14596
+ return this.client.request({
14597
+ path: `customer-portal/invoices${qs ? `?${qs}` : ""}`,
14598
+ responseSchema: customerInvoiceListResponseSchema,
14599
+ headers: this.headers()
14600
+ });
14601
+ }
14602
+ /** The customer's quotes. `status: "sent"` is the set still awaiting them. */
14603
+ async listQuotes(opts) {
14604
+ const params = new URLSearchParams();
14605
+ if (typeof opts?.limit === "number")
14606
+ params.set("limit", String(opts.limit));
14607
+ if (opts?.status) params.set("status", opts.status);
14608
+ const qs = params.toString();
14609
+ return this.client.request({
14610
+ path: `customer-portal/quotes${qs ? `?${qs}` : ""}`,
14611
+ responseSchema: customerQuoteListResponseSchema,
14612
+ headers: this.headers()
14613
+ });
14614
+ }
14615
+ /** The customer's contracts. `status: "sent"` still awaits a signature. */
14616
+ async listContracts(opts) {
14617
+ const params = new URLSearchParams();
14618
+ if (typeof opts?.limit === "number")
14619
+ params.set("limit", String(opts.limit));
14620
+ if (opts?.status) params.set("status", opts.status);
14621
+ const qs = params.toString();
14622
+ return this.client.request({
14623
+ path: `customer-portal/contracts${qs ? `?${qs}` : ""}`,
14624
+ responseSchema: customerContractListResponseSchema,
14625
+ headers: this.headers()
14626
+ });
14627
+ }
14628
+ /**
14629
+ * Every shipment across the customer's orders. `active: true` narrows to
14630
+ * parcels still moving.
14631
+ *
14632
+ * STORED status only — no live carrier poll. `trackShipment(id)` spends a
14633
+ * Shippo request because it is one parcel the customer opened; doing that
14634
+ * per row here would mean a carrier call for every parcel in their history
14635
+ * on every page load.
14636
+ */
14637
+ async listShipments(opts) {
14638
+ const params = new URLSearchParams();
14639
+ if (typeof opts?.limit === "number")
14640
+ params.set("limit", String(opts.limit));
14641
+ if (opts?.active) params.set("active", "1");
14642
+ const qs = params.toString();
14643
+ return this.client.request({
14644
+ path: `customer-portal/shipments${qs ? `?${qs}` : ""}`,
14645
+ responseSchema: customerShipmentListResponseSchema,
14646
+ headers: this.headers()
14647
+ });
14648
+ }
13857
14649
  /**
13858
14650
  * The signed-in customer's orders (newest first), each with a shipment
13859
14651
  * roll-up (`overallStatus`, `anyInTransit`, `latestEstimatedDelivery`) for
@@ -13932,6 +14724,243 @@ var BiabDevCustomerPortalClient = class _BiabDevCustomerPortalClient {
13932
14724
  headers: this.headers()
13933
14725
  });
13934
14726
  }
14727
+ /**
14728
+ * Ask for a replacement instead of a refund.
14729
+ *
14730
+ * Sugar over `submitReturnRequest` with `kind: "exchange"`, because an
14731
+ * exchange reads as its own action to the person writing the UI, and burying
14732
+ * it in an options bag is how it stays undiscovered. `variantId` is the one
14733
+ * they want instead — omit it when that still needs a conversation.
14734
+ *
14735
+ * @example
14736
+ * ```ts
14737
+ * await portal.submitExchangeRequest(orderId, {
14738
+ * exchangeForVariantId: largeVariantId,
14739
+ * reason: "wrong size",
14740
+ * });
14741
+ * ```
14742
+ */
14743
+ async submitExchangeRequest(orderId, input) {
14744
+ return this.submitReturnRequest(orderId, {
14745
+ ...input ?? {},
14746
+ kind: "exchange"
14747
+ });
14748
+ }
14749
+ /**
14750
+ * Report that a parcel never arrived.
14751
+ *
14752
+ * This does NOT change the shipment's carrier status, and deliberately so:
14753
+ * when the carrier says delivered and the customer says otherwise, both
14754
+ * facts matter — the carrier's scan is what the org files a claim against.
14755
+ * The result carries `carrierStatus` alongside the report so a UI can show
14756
+ * both: *"Carrier says delivered Aug 14 · You reported not received Aug 16."*
14757
+ *
14758
+ * `contested: true` means exactly that disagreement. Re-reporting an open
14759
+ * claim returns it with `alreadyOpen: true` rather than erroring — a
14760
+ * customer tapping twice is anxious, not hostile.
14761
+ *
14762
+ * @example
14763
+ * ```ts
14764
+ * const r = await portal.reportNotReceived(shipmentId, {
14765
+ * note: "Nothing on the porch, checked with neighbours.",
14766
+ * });
14767
+ * if (r.contested) showCarrierDisputeHelp();
14768
+ * ```
14769
+ */
14770
+ async reportNotReceived(shipmentId, input) {
14771
+ const body = input?.note ? { note: input.note } : {};
14772
+ return this.client.request({
14773
+ method: "POST",
14774
+ path: `customer-portal/shipments/${encodeURIComponent(shipmentId)}/not-received`,
14775
+ body,
14776
+ responseSchema: customerNotReceivedResultSchema,
14777
+ headers: this.headers()
14778
+ });
14779
+ }
14780
+ /**
14781
+ * The product reviews this customer has written for this org.
14782
+ *
14783
+ * Distinct from `listReviews()`, which is reviews of the ORG. Both exist
14784
+ * because "are these people good to deal with" and "is this thing any good"
14785
+ * are different questions, stored in different tables, and shown in
14786
+ * different places.
14787
+ *
14788
+ * `isApproved: false` means QUEUED, not rejected — render it as "awaiting
14789
+ * review" or the customer will assume it was lost and write it again.
14790
+ */
14791
+ /**
14792
+ * The customer's subscription with this org, and what the org offers.
14793
+ *
14794
+ * One subscription per org — `user_subscriptions` is unique on
14795
+ * (user, org) — so there is no id to pass. The org's live offerings come
14796
+ * back alongside, because a portal that reports "not subscribed" and
14797
+ * nothing else is a dead end.
14798
+ *
14799
+ * **Render entitlement from `subscription.hasAccess`, not from `status`.**
14800
+ * A lifetime purchase has no period to expire and a cancelled subscription
14801
+ * keeps access until the period already paid for ends; `hasAccess` is
14802
+ * computed by the same function the content gates use, so the portal and
14803
+ * the gate cannot disagree.
14804
+ */
14805
+ async getSubscription() {
14806
+ return this.client.request({
14807
+ path: "customer-portal/subscription",
14808
+ responseSchema: customerSubscriptionResponseSchema,
14809
+ headers: this.headers()
14810
+ });
14811
+ }
14812
+ /**
14813
+ * Cancel the subscription at the end of the paid period.
14814
+ *
14815
+ * Cancelling ends the RENEWAL, not the access: the customer has paid for
14816
+ * the period they are in and keeps everything until `accessUntil`. Ending
14817
+ * access on the click would take back something they already bought, which
14818
+ * is the most common way a subscription flow feels like a trap.
14819
+ *
14820
+ * Read `accessUntil` back to them — "active until 14 March" is the true
14821
+ * statement, not "cancelled".
14822
+ */
14823
+ async cancelSubscription() {
14824
+ return this.client.request({
14825
+ method: "POST",
14826
+ path: "customer-portal/subscription/cancel",
14827
+ body: { resume: false },
14828
+ responseSchema: customerSubscriptionCancelResponseSchema,
14829
+ headers: this.headers()
14830
+ });
14831
+ }
14832
+ /**
14833
+ * Clear a pending cancellation.
14834
+ *
14835
+ * Between cancelling and the period ending nothing has actually been lost,
14836
+ * so changing your mind should cost one call rather than a re-purchase.
14837
+ * After the period ends there is nothing to resume and they subscribe again
14838
+ * like anyone else.
14839
+ */
14840
+ async resumeSubscription() {
14841
+ return this.client.request({
14842
+ method: "POST",
14843
+ path: "customer-portal/subscription/cancel",
14844
+ body: { resume: true },
14845
+ responseSchema: customerSubscriptionCancelResponseSchema,
14846
+ headers: this.headers()
14847
+ });
14848
+ }
14849
+ /**
14850
+ * The content this subscription entitles them to — the answer to "what am
14851
+ * I actually getting for this?", which is the question asked right before
14852
+ * someone cancels.
14853
+ *
14854
+ * When `entitled` is false these are LOCKED previews, not an empty
14855
+ * entitlement: titles, excerpts and images, no bodies. Show them beside the
14856
+ * offer. Rendering an empty list would hide the pitch at exactly the moment
14857
+ * it is most relevant.
14858
+ */
14859
+ async getSubscriberContent(opts) {
14860
+ const params = new URLSearchParams();
14861
+ if (typeof opts?.limit === "number")
14862
+ params.set("limit", String(opts.limit));
14863
+ const qs = params.toString();
14864
+ return this.client.request({
14865
+ path: `customer-portal/subscription/content${qs ? `?${qs}` : ""}`,
14866
+ responseSchema: customerSubscriberContentResponseSchema,
14867
+ headers: this.headers()
14868
+ });
14869
+ }
14870
+ /**
14871
+ * Push config and the browsers this customer has registered.
14872
+ *
14873
+ * Returns `vapidPublicKey` too, because a page cannot subscribe without it.
14874
+ */
14875
+ async getPushConfig() {
14876
+ return this.client.request({
14877
+ path: "customer-portal/push",
14878
+ responseSchema: customerPushConfigSchema,
14879
+ headers: this.headers()
14880
+ });
14881
+ }
14882
+ /**
14883
+ * Register this browser.
14884
+ *
14885
+ * Pair with `subscribeToPush()` from `@businessdash/sdk/push-core`, which
14886
+ * handles the service worker, the permission prompt and the key encoding
14887
+ * and hands back exactly this payload.
14888
+ *
14889
+ * Upserted on the endpoint, so re-subscribing from the same browser
14890
+ * refreshes the row rather than creating a second one.
14891
+ */
14892
+ async subscribePush(input) {
14893
+ return this.client.request({
14894
+ method: "POST",
14895
+ path: "customer-portal/push",
14896
+ body: input,
14897
+ responseSchema: external_exports.object({ id: external_exports.string(), created: external_exports.boolean() }),
14898
+ headers: this.headers()
14899
+ });
14900
+ }
14901
+ /**
14902
+ * Rename a device, or narrow what it receives.
14903
+ *
14904
+ * `categories: []` means "nothing for now" and keeps the subscription
14905
+ * warm — browsers make re-granting a revoked permission deliberately
14906
+ * awkward, so an "off" that discards the subscription is hard to undo.
14907
+ */
14908
+ async updatePushDevice(input) {
14909
+ return this.client.request({
14910
+ method: "PATCH",
14911
+ path: "customer-portal/push",
14912
+ body: input,
14913
+ responseSchema: external_exports.object({ ok: external_exports.boolean() }),
14914
+ headers: this.headers()
14915
+ });
14916
+ }
14917
+ /**
14918
+ * Forget a device. Takes an id or the endpoint.
14919
+ *
14920
+ * A browser tearing its own subscription down knows its endpoint, not our
14921
+ * row id — so pass what `unsubscribeFromPush()` returns.
14922
+ */
14923
+ async unsubscribePush(input) {
14924
+ return this.client.request({
14925
+ method: "DELETE",
14926
+ path: "customer-portal/push",
14927
+ body: input,
14928
+ responseSchema: external_exports.object({
14929
+ ok: external_exports.boolean(),
14930
+ deletedId: external_exports.string().nullable()
14931
+ }),
14932
+ headers: this.headers()
14933
+ });
14934
+ }
14935
+ async listProductReviews() {
14936
+ return this.client.request({
14937
+ path: "customer-portal/product-reviews",
14938
+ responseSchema: customerProductReviewListSchema,
14939
+ headers: this.headers()
14940
+ });
14941
+ }
14942
+ /**
14943
+ * Review a product this customer BOUGHT.
14944
+ *
14945
+ * The portal requires a matching order — it is standing inside the
14946
+ * customer's purchase history, which is the one thing the public storefront
14947
+ * does not know. That makes these verified-buyer reviews, and it stops a
14948
+ * competitor one-starring a catalogue they never bought.
14949
+ *
14950
+ * Rejects with `not_purchased` (403) when no order matches, and
14951
+ * `already_reviewed` (409) on a second review of the same product.
14952
+ * Moderation follows the ORG's policy, so the result may be
14953
+ * `awaitingModeration`.
14954
+ */
14955
+ async submitProductReview(input) {
14956
+ return this.client.request({
14957
+ method: "POST",
14958
+ path: "customer-portal/product-reviews",
14959
+ body: input,
14960
+ responseSchema: customerProductReviewCreatedSchema,
14961
+ headers: this.headers()
14962
+ });
14963
+ }
13935
14964
  /**
13936
14965
  * List the digital downloads the customer is entitled to for a paid order
13937
14966
  * (P10d). Each item is a ready-to-use URL — a short-lived presigned link for
@@ -14027,6 +15056,22 @@ var BiabDevCustomerPortalClient = class _BiabDevCustomerPortalClient {
14027
15056
  * dispatch travel-time recompute layer ships, at which point the
14028
15057
  * `eta` field switches sources without breaking this shape.
14029
15058
  */
15059
+ /**
15060
+ * Where the job and its technicians are in the dispatch lifecycle.
15061
+ *
15062
+ * Named for ETA historically; it is the DISPATCH STATUS surface, which is
15063
+ * why `getDispatchStatus` below is the same call under the name people
15064
+ * look for.
15065
+ *
15066
+ * Read `dispatchStatus` (job-level) for "is anyone on the way" and
15067
+ * `assignments[].dispatchStatus` for per-technician detail. They differ on
15068
+ * purpose: the job is `completed` only once the LAST assignee finishes.
15069
+ *
15070
+ * Nothing about the dispatch CASCADE is exposed — who was offered the job,
15071
+ * who declined, how many people were asked before someone accepted. That
15072
+ * is staff-internal, and a customer learning they were the fourth choice
15073
+ * helps nobody.
15074
+ */
14030
15075
  async getJobEta(jobId) {
14031
15076
  return this.client.request({
14032
15077
  path: `customer-portal/jobs/${encodeURIComponent(jobId)}/eta`,
@@ -14034,6 +15079,16 @@ var BiabDevCustomerPortalClient = class _BiabDevCustomerPortalClient {
14034
15079
  headers: this.headers()
14035
15080
  });
14036
15081
  }
15082
+ /**
15083
+ * Dispatch status for a job — the same call as `getJobEta`, under the name
15084
+ * developers actually search for.
15085
+ *
15086
+ * An alias rather than a second route: two endpoints returning the same
15087
+ * thing is how they drift.
15088
+ */
15089
+ async getDispatchStatus(jobId) {
15090
+ return this.getJobEta(jobId);
15091
+ }
14037
15092
  /**
14038
15093
  * Unified job activity feed: structured events (status changes,
14039
15094
  * dispatch lifecycle, media uploads, quote/contract/invoice
@@ -14139,6 +15194,190 @@ var BiabDevAuthClient = class {
14139
15194
  });
14140
15195
  }
14141
15196
  };
15197
+ var BiabDevCustomerInvitesClient = class {
15198
+ constructor(client) {
15199
+ this.client = client;
15200
+ }
15201
+ client;
15202
+ /**
15203
+ * Hand an invite link out again.
15204
+ *
15205
+ * **Rotates the token** — the previous link stops working. That is the
15206
+ * point rather than a side effect: if the reason for resending was "it went
15207
+ * to the wrong address", rotating IS the fix, and reusing the token would
15208
+ * leave the wrong recipient holding a working invitation. The cost is that
15209
+ * someone who finds the original email later gets a dead link, which is a
15210
+ * support message rather than an account.
15211
+ *
15212
+ * Rate limited to one send a minute per invitation, answering **429** with
15213
+ * a retry hint. Resend mails an address the caller chose, so an unbounded
15214
+ * one is a mail-bombing tool. Staff clicking the button in the dashboard
15215
+ * skip the wait; an API key does not, because an API key is the automated
15216
+ * caller the limit exists for.
15217
+ *
15218
+ * Refuses a **revoked** invitation (resending would quietly un-revoke it)
15219
+ * and a **fully-redeemed** one (it did its job; a new invitation should be
15220
+ * created as one, so the list keeps showing what happened).
15221
+ */
15222
+ async resend(inviteId, opts) {
15223
+ return this.client.request({
15224
+ method: "POST",
15225
+ path: `customer-invites/${encodeURIComponent(inviteId)}/resend`,
15226
+ body: opts?.expiresInDays === void 0 ? {} : { expiresInDays: opts.expiresInDays },
15227
+ responseSchema: customerInviteResendResponseSchema
15228
+ });
15229
+ }
15230
+ };
15231
+ var BiabDevSchedulingClient = class {
15232
+ constructor(client, siteId) {
15233
+ this.client = client;
15234
+ this.siteId = siteId;
15235
+ }
15236
+ client;
15237
+ siteId;
15238
+ path(suffix) {
15239
+ return `sites/${encodeURIComponent(this.siteId)}/scheduling/${suffix}`;
15240
+ }
15241
+ /** What the org offers to book. */
15242
+ async listEventTypes() {
15243
+ return this.client.request({
15244
+ path: this.path("event-types"),
15245
+ responseSchema: schedulingEventTypeListSchema
15246
+ });
15247
+ }
15248
+ /** One event type, plus the questions asked when booking it. */
15249
+ async getEventType(slug) {
15250
+ return this.client.request({
15251
+ path: this.path(`event-types/${encodeURIComponent(slug)}`),
15252
+ responseSchema: schedulingEventTypeDetailSchema
15253
+ });
15254
+ }
15255
+ /**
15256
+ * Free slots in a window.
15257
+ *
15258
+ * Ask for the window you are about to render, not the whole month: slot
15259
+ * computation walks every host's calendar and busy times, so a wide range
15260
+ * is a slow one.
15261
+ */
15262
+ async getAvailableSlots(slug, params) {
15263
+ const query = new URLSearchParams({
15264
+ from: typeof params.from === "string" ? params.from : params.from.toISOString(),
15265
+ to: typeof params.to === "string" ? params.to : params.to.toISOString()
15266
+ });
15267
+ return this.client.request({
15268
+ path: this.path(
15269
+ `event-types/${encodeURIComponent(slug)}/slots?${query.toString()}`
15270
+ ),
15271
+ responseSchema: schedulingSlotsResponseSchema
15272
+ });
15273
+ }
15274
+ /**
15275
+ * Book a slot.
15276
+ *
15277
+ * Returns `pending` rather than `confirmed` when the event type requires
15278
+ * approval — say "requested" in the UI for that case, because telling
15279
+ * someone their meeting is booked when staff still have to accept it is the
15280
+ * kind of thing they plan a day around.
15281
+ */
15282
+ async confirmBooking(input) {
15283
+ const body = {
15284
+ ...input,
15285
+ startAt: typeof input.startAt === "string" ? input.startAt : input.startAt.toISOString()
15286
+ };
15287
+ return this.client.request({
15288
+ method: "POST",
15289
+ path: this.path("bookings"),
15290
+ body,
15291
+ responseSchema: schedulingBookingResultSchema
15292
+ });
15293
+ }
15294
+ /**
15295
+ * Read a booking with one of its signed tokens.
15296
+ *
15297
+ * `type` must match the token you hold — a cancel token will not open the
15298
+ * manage view. That is the point of issuing three.
15299
+ */
15300
+ async getBooking(token, type = "manage") {
15301
+ return this.client.request({
15302
+ path: this.path(
15303
+ `bookings/by-token/${encodeURIComponent(token)}?type=${encodeURIComponent(type)}`
15304
+ ),
15305
+ responseSchema: schedulingBookingViewSchema
15306
+ });
15307
+ }
15308
+ /**
15309
+ * Move a booking — the INVITEE side, with their reschedule token.
15310
+ *
15311
+ * Notifies the invitee and every host, and cancels the reminder jobs queued
15312
+ * against the old time so nobody gets "your meeting starts in 15 minutes"
15313
+ * for a slot that moved.
15314
+ */
15315
+ async rescheduleBooking(input) {
15316
+ return this.client.request({
15317
+ method: "POST",
15318
+ path: this.path(`bookings/by-token/${encodeURIComponent(input.token)}`),
15319
+ body: {
15320
+ action: "reschedule",
15321
+ newStartAt: typeof input.newStartAt === "string" ? input.newStartAt : input.newStartAt.toISOString(),
15322
+ ...input.reason ? { reason: input.reason } : {}
15323
+ },
15324
+ responseSchema: schedulingRescheduleResultSchema
15325
+ });
15326
+ }
15327
+ /**
15328
+ * Move a booking as STAFF, with the API key rather than an invitee token.
15329
+ *
15330
+ * Same service as the token path, so the invitee AND every host are
15331
+ * notified either way, and the reminder jobs for the old time are
15332
+ * cancelled either way. `actorUserId` records WHO moved it, which is what
15333
+ * lets a customer's history say "they rescheduled" rather than leaving an
15334
+ * unexplained change.
15335
+ */
15336
+ async rescheduleBookingAsStaff(input) {
15337
+ return this.client.request({
15338
+ method: "POST",
15339
+ path: this.path(`bookings/${encodeURIComponent(input.bookingId)}/manage`),
15340
+ body: {
15341
+ action: "reschedule",
15342
+ newStartAt: typeof input.newStartAt === "string" ? input.newStartAt : input.newStartAt.toISOString(),
15343
+ ...input.reason ? { reason: input.reason } : {},
15344
+ ...input.actorUserId ? { actorUserId: input.actorUserId } : {}
15345
+ },
15346
+ responseSchema: schedulingRescheduleResultSchema
15347
+ });
15348
+ }
15349
+ /** Cancel a booking as STAFF. Notifies the invitee and every host. */
15350
+ async cancelBookingAsStaff(input) {
15351
+ return this.client.request({
15352
+ method: "POST",
15353
+ path: this.path(`bookings/${encodeURIComponent(input.bookingId)}/manage`),
15354
+ body: {
15355
+ action: "cancel",
15356
+ ...input.reason ? { reason: input.reason } : {},
15357
+ ...input.actorUserId ? { actorUserId: input.actorUserId } : {}
15358
+ },
15359
+ responseSchema: schedulingCancelResultSchema
15360
+ });
15361
+ }
15362
+ /**
15363
+ * Cancel a booking — the INVITEE side, with their cancel token.
15364
+ *
15365
+ * `reason` is passed to the hosts. Worth collecting: "something came up" and
15366
+ * "I booked the wrong service" lead to different follow-ups, and the second
15367
+ * is recoverable revenue.
15368
+ */
15369
+ async cancelBooking(input) {
15370
+ return this.client.request({
15371
+ method: "POST",
15372
+ path: this.path(`bookings/by-token/${encodeURIComponent(input.token)}`),
15373
+ body: {
15374
+ action: "cancel",
15375
+ ...input.reason ? { reason: input.reason } : {}
15376
+ },
15377
+ responseSchema: schedulingCancelResultSchema
15378
+ });
15379
+ }
15380
+ };
14142
15381
 
14143
15382
  // src/auth-handler.ts
14144
15383
  var DEFAULT_AUTH_COOKIE_NAME = "biab_session";