@whooshbang/sdk 5.0.0 → 6.0.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.
Files changed (67) hide show
  1. package/README.md +232 -83
  2. package/dist/cli/commands.js +2 -0
  3. package/dist/cli/commands.js.map +1 -1
  4. package/dist/client.d.ts +209 -1
  5. package/dist/client.js +540 -5
  6. package/dist/client.js.map +1 -1
  7. package/dist/index.d.ts +2 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/interactions.js +18 -3
  10. package/dist/interactions.js.map +1 -1
  11. package/dist/recipient/element.js +641 -14
  12. package/dist/recipient/element.js.map +1 -1
  13. package/dist/recipient/i18n/ar.js +77 -0
  14. package/dist/recipient/i18n/ar.js.map +1 -1
  15. package/dist/recipient/i18n/catalog.d.ts +75 -0
  16. package/dist/recipient/i18n/catalog.js.map +1 -1
  17. package/dist/recipient/i18n/de.js +82 -0
  18. package/dist/recipient/i18n/de.js.map +1 -1
  19. package/dist/recipient/i18n/en.js +82 -0
  20. package/dist/recipient/i18n/en.js.map +1 -1
  21. package/dist/recipient/i18n/es.js +82 -0
  22. package/dist/recipient/i18n/es.js.map +1 -1
  23. package/dist/recipient/i18n/fa.js +77 -0
  24. package/dist/recipient/i18n/fa.js.map +1 -1
  25. package/dist/recipient/i18n/fr.js +82 -0
  26. package/dist/recipient/i18n/fr.js.map +1 -1
  27. package/dist/recipient/i18n/hi.js +82 -0
  28. package/dist/recipient/i18n/hi.js.map +1 -1
  29. package/dist/recipient/i18n/id.js +82 -0
  30. package/dist/recipient/i18n/id.js.map +1 -1
  31. package/dist/recipient/i18n/it.js +82 -0
  32. package/dist/recipient/i18n/it.js.map +1 -1
  33. package/dist/recipient/i18n/nl.js +82 -0
  34. package/dist/recipient/i18n/nl.js.map +1 -1
  35. package/dist/recipient/i18n/pl.js +82 -0
  36. package/dist/recipient/i18n/pl.js.map +1 -1
  37. package/dist/recipient/i18n/pt-BR.js +82 -0
  38. package/dist/recipient/i18n/pt-BR.js.map +1 -1
  39. package/dist/recipient/i18n/ru.js +82 -0
  40. package/dist/recipient/i18n/ru.js.map +1 -1
  41. package/dist/recipient/i18n/tr.js +82 -0
  42. package/dist/recipient/i18n/tr.js.map +1 -1
  43. package/dist/recipient/i18n/uk.js +82 -0
  44. package/dist/recipient/i18n/uk.js.map +1 -1
  45. package/dist/recipient/i18n/zh-Hans.js +77 -0
  46. package/dist/recipient/i18n/zh-Hans.js.map +1 -1
  47. package/dist/recipient/order-section.d.ts +41 -0
  48. package/dist/recipient/order-section.js +547 -0
  49. package/dist/recipient/order-section.js.map +1 -0
  50. package/dist/recipient/order-view.d.ts +123 -0
  51. package/dist/recipient/order-view.js +304 -0
  52. package/dist/recipient/order-view.js.map +1 -0
  53. package/dist/recipient/platform-mark.d.ts +1 -0
  54. package/dist/recipient/platform-mark.js +57 -0
  55. package/dist/recipient/platform-mark.js.map +1 -0
  56. package/dist/recipient/quiet-section.d.ts +47 -0
  57. package/dist/recipient/quiet-section.js +490 -0
  58. package/dist/recipient/quiet-section.js.map +1 -0
  59. package/dist/recipient/quiet-view.d.ts +84 -0
  60. package/dist/recipient/quiet-view.js +250 -0
  61. package/dist/recipient/quiet-view.js.map +1 -0
  62. package/dist/recipient/view.d.ts +2 -0
  63. package/dist/recipient/view.js.map +1 -1
  64. package/dist/webhooks.d.ts +30 -1
  65. package/dist/webhooks.js +57 -4
  66. package/dist/webhooks.js.map +1 -1
  67. package/package.json +12 -2
package/dist/client.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { validateWhoAmI, validateOperatorCollection, validateOperatorResolution, validateCreateOperatorMessageRequest, validateOperatorMessageResult, validateOperatorBroadcast, validateOperatorPreferences, validateOperatorConnectRequest, } from "@whooshbang/contracts";
2
2
  import { validateAssertEmailConsentRequest, validateBindingSummary, } from "@whooshbang/contracts";
3
- import { contractValidationErrors, validateOrganizationCredential, validateOrganizationCredentialCollection, validateOrganizationCredentialRotation, validateOrganizationCredentialSecretReveal, validateBillingProjectSlots, validateBillingPromotions, validateBillingPromotion, validateRedeemBillingPromotionRequest, validateAssignBillingProjectSlotsRequest, validateSubscriptionChange, validateConfirmSubscriptionChangeRequest, validateBillingEntitlements, validateSubscriptionSelection, validateProjectAttribution, validateUpdateProjectAttributionRequest, validateAutoTopUpSettings, validateUpdateAutoTopUpSettingsRequest, validateBillingAccount, validateCardSetup, validateCreateCreditPurchaseRequest, validateCreditPurchase, validateBillingInvoiceCollection, validateUpdateBillingReceiptEmailRequest, validateOrganizationProjection, validateApiCredential, validateApiCredentialCollection, validateApiCredentialRotation, validateApiCredentialSecretReveal, validateAttachNotifierConnectionRequest, validateChannelConnection, validateChannelConnectionCollection, validateConnectionProviderCollection, validateUsageReport, validateMessageListPage, validateMessageDeliveryHistory, validateMessageNotificationImage, validateInteractionTimeline, validateUpdateEmailSenderRequest, validateCustomerEventDeliveryHistory, validateCustomerEventDeliveryAttempt, validateDeliveryHolds, validateMachineClientOperationsList, validateRecipientCopyCatalogue, validateNotifierConnectionCollection, validateProjectRecipientExperience, validateRecipientBrandLogoUpload, validateNotificationImageAsset, validateUpdateProjectRecipientExperienceRequest, validateEnvironmentRecipientExperience, validateUpdateEnvironmentRecipientExperienceRequest, validateSubscriberChannelSettings, validateAcknowledgeEmailRemediationRequest, validateCreateRecipientSessionRequest, validateCreateRecipientSessionResponse, validateRecipientSession, validateCreateProviderHandoffRequest, validateProviderHandoff, validateSetPreferredBindingRequest, validatePreferredBinding, validateCreateSubscriberRequest, validateSubscriber, validateSubscriberDataExport, validateUpdateSubscriberRequest, validateSubscriberCollection, validateCloseOrganizationRequest, validateInviteTeammateRequest, validateTeammate, validateTeammateAccessRequest, validateTeammateCollection, validateOrganizationClosureResult, validateCreateSubscriberGroupRequest, validateUpdateSubscriberGroupRequest, validateSubscriberGroup, validateSubscriberGroupCollection, validateSubscriberGroupMembership, validateSubscriberGroupMembershipCollection, validateCreateGroupBroadcastRequest, validateGroupBroadcast, validateCreateOrganizationCredentialRequest, validateCreateApiCredentialRequest, validateCreateChannelConnectionRequest, validateCreateCustomerEndpointRequest, validateCreateMachineClientRequest, validateCreateMessageRequest, validateMessageCategory, validateMessageCategoryCollection, validateCreateMessageCategoryRequest, validateUpdateMessageCategoryRequest, validateSubscriberCategoryPreference, validateSubscriberCategoryPreferenceCollection, validateSetSubscriberCategoryPreferenceRequest, validateCreateProjectRequest, validateUpdateProjectRequest, validateCreateSubscriptionLinkRequest, validateCustomerEndpoint, validateCustomerEndpointAttemptCollection, validateCustomerEndpointCollection, validateCustomerEndpointMutationResult, validateInteractionSummary, validateMachineClient, validateMachineCredential, validateMachineEventAckRequest, validateMachineEventAckResponse, validateMachineEventPollResponse, validateMessage, validateProblem, validateProject, validateProjectCollection, validateRecipientCopyOverride, validateRecipientCopyOverrideCollection, validateProviderCapabilitiesCollection, validateProviderInstallationCollection, validateEmailDomainCollection, validateCreateEmailDomainRequest, validateRegisterMachineCredentialRequest, validateRotateOrganizationCredentialRequest, validateRotateApiCredentialRequest, validateConnectionTest, validateConnectionTestCollection, validateCreateConnectionTestRequest, validateCustomerApplicationManifest, validateRotateChannelConnectionCredentialRequest, validateRotateCustomerEndpointRequest, validateSubscriptionLink, validateUpdateChannelConnectionRequest, validateUpdateRecipientCopyOverrideRequest, } from "@whooshbang/contracts";
3
+ import { contractValidationErrors, validateOrganizationCredential, validateOrganizationCredentialCollection, validateOrganizationCredentialRotation, validateOrganizationCredentialSecretReveal, validateBillingProjectSlots, validateBillingPromotions, validateBillingPromotion, validateRedeemBillingPromotionRequest, validateAssignBillingProjectSlotsRequest, validateSubscriptionChange, validateConfirmSubscriptionChangeRequest, validateBillingEntitlements, validateSubscriptionSelection, validateProjectAttribution, validateUpdateProjectAttributionRequest, validateAutoTopUpSettings, validateUpdateAutoTopUpSettingsRequest, validateBillingAccount, validateCardSetup, validateCreateCreditPurchaseRequest, validateCreditPurchase, validateBillingInvoiceCollection, validateUpdateBillingReceiptEmailRequest, validateOrganizationProjection, validateApiCredential, validateApiCredentialCollection, validateApiCredentialRotation, validateApiCredentialSecretReveal, validateAttachNotifierConnectionRequest, validateChannelConnection, validateChannelConnectionCollection, validateConnectionProviderCollection, validateUsageReport, validateMessageListPage, validateMessageDeliveryHistory, validateMessageNotificationImage, validateInteractionTimeline, validateUpdateEmailSenderRequest, validateCustomerEventDeliveryHistory, validateCustomerEventDeliveryAttempt, validateDeliveryHolds, validateMachineClientOperationsList, validateRecipientCopyCatalogue, validateNotifierConnectionCollection, validateProjectRecipientExperience, validateRecipientBrandLogoUpload, validateNotificationImageAsset, validateUpdateProjectRecipientExperienceRequest, validateEnvironmentRecipientExperience, validateUpdateEnvironmentRecipientExperienceRequest, validateSubscriberChannelSettings, validateAcknowledgeEmailRemediationRequest, validateCreateRecipientSessionRequest, validateCreateRecipientSessionResponse, validateRecipientSession, validateCreateProviderHandoffRequest, validateProviderHandoff, validateSetPreferredBindingRequest, validatePreferredBinding, validateCreateSubscriberRequest, validateSubscriber, validateSubscriberDataExport, validateUpdateSubscriberRequest, validateSubscriberCollection, validateCloseOrganizationRequest, validateInviteTeammateRequest, validateTeammate, validateTeammateAccessRequest, validateTeammateCollection, validateOrganizationClosureResult, validateCreateSubscriberGroupRequest, validateUpdateSubscriberGroupRequest, validateSubscriberGroup, validateSubscriberGroupCollection, validateSubscriberGroupMembership, validateSubscriberGroupMembershipCollection, validateCreateGroupBroadcastRequest, validateGroupBroadcast, validateCreateOrganizationCredentialRequest, validateCreateApiCredentialRequest, validateCreateChannelConnectionRequest, validateCreateCustomerEndpointRequest, validateCreateMachineClientRequest, validateCreateMessageRequest, validateCancelEscalationByKeyRequest, validateEscalationPathPreview, validateEscalationOrder, validateEscalationOrderCollection, validateSaveEscalationOrderRequest, validateQuietHours, validateSaveQuietHoursRequest, validateEscalationPolicy, validateEscalationPolicyCollection, validateEscalationLimits, validateUpdateEscalationLimitsRequest, validateEscalationPagingLimitReport, validateUpdateEscalationPolicyRequest, validateCancelEscalationRequest, validateEscalation, validateMessageCategory, validateMessageCategoryCollection, validateCreateMessageCategoryRequest, validateUpdateMessageCategoryRequest, validateSubscriberCategoryPreference, validateSubscriberCategoryPreferenceCollection, validateSetSubscriberCategoryPreferenceRequest, validateCreateProjectRequest, validateUpdateProjectRequest, validateCreateSubscriptionLinkRequest, validateCustomerEndpoint, validateCustomerEndpointAttemptCollection, validateCustomerEndpointCollection, validateCustomerEndpointMutationResult, validateInteractionSummary, validateMachineClient, validateMachineCredential, validateMachineEventAckRequest, validateMachineEventAckResponse, validateMachineEventPollResponse, validateMessage, validateProblem, validateProject, validateProjectCollection, validateRecipientCopyOverride, validateRecipientCopyOverrideCollection, validateProviderCapabilitiesCollection, validateProviderInstallationCollection, validateEmailDomainCollection, validateCreateEmailDomainRequest, validateRegisterMachineCredentialRequest, validateRotateOrganizationCredentialRequest, validateRotateApiCredentialRequest, validateConnectionTest, validateConnectionTestCollection, validateCreateConnectionTestRequest, validateCustomerApplicationManifest, validateRotateChannelConnectionCredentialRequest, validateRotateCustomerEndpointRequest, validateSubscriptionLink, validateUpdateChannelConnectionRequest, validateUpdateRecipientCopyOverrideRequest, } from "@whooshbang/contracts";
4
4
  import { validateAdditiveCompatible } from "./additive-compatibility.js";
5
- import { WhooshBangContractError, WhooshBangOutcomeUnknownError, WhooshBangProblemError, WhooshBangProtocolError, WhooshBangTransportError, validationError, } from "./errors.js";
5
+ import { WhooshBangContractError, WhooshBangOutcomeUnknownError, WhooshBangProblemError, WhooshBangProtocolError, WhooshBangTransportError, WhooshBangValidationError, validationError, } from "./errors.js";
6
6
  import { interactionAnswer } from "./interactions.js";
7
7
  const MAX_RESPONSE_BYTES = 1024 * 1024;
8
8
  /**
@@ -79,6 +79,42 @@ function usageQuery(operation, options) {
79
79
  }
80
80
  return search.size === 0 ? "" : `?${search.toString()}`;
81
81
  }
82
+ const templateRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
83
+ function validateTemplateCatalog(value) {
84
+ return (templateRecord(value) &&
85
+ Array.isArray(value.items) &&
86
+ value.items.length <= 100 &&
87
+ Array.isArray(value.categories) &&
88
+ value.categories.every((category) => typeof category === "string") &&
89
+ (value.next_cursor === null || typeof value.next_cursor === "string") &&
90
+ Number.isSafeInteger(value.total) &&
91
+ Number.isSafeInteger(value.page) &&
92
+ Number.isSafeInteger(value.page_size) &&
93
+ value.items.every((item) => validateTemplateCatalogEntry(item)));
94
+ }
95
+ function validateTemplateCatalogEntry(item) {
96
+ return (templateRecord(item) &&
97
+ typeof item.id === "string" &&
98
+ typeof item.name === "string" &&
99
+ typeof item.displayName === "string" &&
100
+ typeof item.description === "string" &&
101
+ typeof item.category === "string" &&
102
+ typeof item.disabled === "boolean" &&
103
+ Number.isSafeInteger(item.latestPublishedRevision) &&
104
+ templateRecord(item.draft) &&
105
+ (item.published === undefined ||
106
+ (templateRecord(item.published) &&
107
+ Number.isSafeInteger(item.published.revision) &&
108
+ templateRecord(item.published.definition))));
109
+ }
110
+ function validateTemplateMessageSendResult(value) {
111
+ return (templateRecord(value) &&
112
+ validateMessage(value.message) &&
113
+ templateRecord(value.template) &&
114
+ typeof value.template.id === "string" &&
115
+ Number.isSafeInteger(value.template.revision) &&
116
+ typeof value.template.locale === "string");
117
+ }
82
118
  async function readBoundedBytes(response, operation, maximumBytes) {
83
119
  const length = response.headers.get("content-length");
84
120
  if (length !== null &&
@@ -485,10 +521,16 @@ async function messageCreation(send) {
485
521
  * response; the resource validators alone do not, because the field is an
486
522
  * endpoint-level promise rather than part of the resource.
487
523
  */
524
+ const CANCELLATION_RESPONSE_PATHS = {
525
+ cancelEscalation: "~1v1~1escalations~1{escalation_id}~1cancel",
526
+ cancelEscalationByKey: "~1v1~1escalations~1cancel",
527
+ cancelEscalationByKeyInEnvironment: "~1v1~1projects~1{project_id}~1environments~1{environment_id}~1escalations~1cancel",
528
+ cancelEscalationInEnvironment: "~1v1~1projects~1{project_id}~1environments~1{environment_id}~1escalations~1{escalation_id}~1cancel",
529
+ cancelMessage: "~1v1~1messages~1{message_id}~1cancel",
530
+ cancelSubscriptionLink: "~1v1~1subscription-links~1{subscription_link_id}~1cancel",
531
+ };
488
532
  function cancellationEffectiveMissing(operationId) {
489
- const path = operationId === "cancelMessage"
490
- ? "~1v1~1messages~1{message_id}~1cancel"
491
- : "~1v1~1subscription-links~1{subscription_link_id}~1cancel";
533
+ const path = CANCELLATION_RESPONSE_PATHS[operationId];
492
534
  return {
493
535
  instancePath: "",
494
536
  keyword: "required",
@@ -497,6 +539,16 @@ function cancellationEffectiveMissing(operationId) {
497
539
  schemaPath: `#/paths/${path}/post/responses/200/content/application~1json/schema/allOf/1/required`,
498
540
  };
499
541
  }
542
+ /** Reads a cancellation response's `cancellation_effective` as the outcome. */
543
+ function escalationCancelOutcome(operation, escalation) {
544
+ if (escalation.cancellation_effective === true) {
545
+ return { escalation, outcome: "cancelled" };
546
+ }
547
+ if (escalation.cancellation_effective === false) {
548
+ return { escalation, outcome: "already_closed" };
549
+ }
550
+ throw new WhooshBangContractError(operation, [cancellationEffectiveMissing(operation)], "The cancellation response did not say whether cancellation took effect.");
551
+ }
500
552
  function describeFailure(error) {
501
553
  if (error instanceof WhooshBangProblemError) {
502
554
  return {
@@ -1370,6 +1422,61 @@ export class WhooshBangClient {
1370
1422
  validator: validateMessageCategoryCollection,
1371
1423
  });
1372
1424
  }
1425
+ async listMessageTemplates(projectId, query = {}, options = {}) {
1426
+ const operation = "listMessageTemplates";
1427
+ const params = new URLSearchParams({ executable_only: "true" });
1428
+ if (query.search !== undefined)
1429
+ params.set("search", query.search);
1430
+ if (query.category !== undefined)
1431
+ params.set("category", query.category);
1432
+ if (query.after !== undefined)
1433
+ params.set("after", query.after);
1434
+ if (query.limit !== undefined)
1435
+ params.set("limit", String(query.limit));
1436
+ if (query.page !== undefined)
1437
+ params.set("page", String(query.page));
1438
+ return this.#request({
1439
+ method: "GET",
1440
+ operation,
1441
+ options,
1442
+ sideEffect: false,
1443
+ path: `v1/projects/${pathSegment(operation, projectId, "projectId")}/message-templates?${params}`,
1444
+ validator: validateTemplateCatalog,
1445
+ strictResponse: true,
1446
+ });
1447
+ }
1448
+ async sendTemplateMessage(projectId, environmentId, request, options = {}) {
1449
+ const operation = "sendTemplateMessage";
1450
+ if (!request.template ||
1451
+ !templateRecord(request.input) ||
1452
+ !request.to.subscriber_id)
1453
+ throw new WhooshBangValidationError(operation, [
1454
+ { path: "/template", code: "required" },
1455
+ ]);
1456
+ return this.#request({
1457
+ body: request,
1458
+ method: "POST",
1459
+ operation,
1460
+ options,
1461
+ idempotencyKey: options.idempotencyKey,
1462
+ sideEffect: true,
1463
+ path: `${environmentRoot(operation, projectId, environmentId)}/template-messages`,
1464
+ validator: validateTemplateMessageSendResult,
1465
+ strictResponse: true,
1466
+ });
1467
+ }
1468
+ async getMessageTemplate(projectId, reference, options = {}) {
1469
+ const operation = "getMessageTemplate";
1470
+ return this.#request({
1471
+ method: "GET",
1472
+ operation,
1473
+ options,
1474
+ sideEffect: false,
1475
+ path: `v1/projects/${pathSegment(operation, projectId, "projectId")}/message-templates/${pathSegment(operation, reference, "reference")}`,
1476
+ validator: validateTemplateCatalogEntry,
1477
+ strictResponse: true,
1478
+ });
1479
+ }
1373
1480
  async createMessageCategory(projectId, request, options = {}) {
1374
1481
  const operation = "createMessageCategory";
1375
1482
  assertInput(operation, request, validateCreateMessageCategoryRequest);
@@ -1432,6 +1539,88 @@ export class WhooshBangClient {
1432
1539
  validator: validateSubscriberCategoryPreference,
1433
1540
  });
1434
1541
  }
1542
+ /**
1543
+ * The signed-in teammate's own escalation order for each urgency
1544
+ * (FXO-3673); never another person's.
1545
+ */
1546
+ async getOwnEscalationOrders(projectId, environmentId, options = {}) {
1547
+ const operation = "getOwnEscalationOrders";
1548
+ return this.#request({
1549
+ method: "GET",
1550
+ operation,
1551
+ options,
1552
+ path: `${environmentRoot(operation, projectId, environmentId)}/notification-preferences/escalation-orders`,
1553
+ sideEffect: false,
1554
+ validator: validateEscalationOrderCollection,
1555
+ });
1556
+ }
1557
+ /** Saves the signed-in teammate's own order for one urgency (FXO-3673). */
1558
+ async saveOwnEscalationOrder(projectId, environmentId, level, request, options = {}) {
1559
+ const operation = "saveOwnEscalationOrder";
1560
+ assertInput(operation, request, validateSaveEscalationOrderRequest);
1561
+ return this.#request({
1562
+ body: request,
1563
+ method: "PUT",
1564
+ operation,
1565
+ options,
1566
+ path: `${environmentRoot(operation, projectId, environmentId)}/notification-preferences/escalation-orders/${pathSegment(operation, level, "level")}`,
1567
+ sideEffect: true,
1568
+ validator: validateEscalationOrder,
1569
+ });
1570
+ }
1571
+ /** Returns the signed-in teammate to the project's order for one urgency. */
1572
+ async resetOwnEscalationOrder(projectId, environmentId, level, options = {}) {
1573
+ const operation = "resetOwnEscalationOrder";
1574
+ return this.#request({
1575
+ method: "DELETE",
1576
+ operation,
1577
+ options,
1578
+ path: `${environmentRoot(operation, projectId, environmentId)}/notification-preferences/escalation-orders/${pathSegment(operation, level, "level")}`,
1579
+ sideEffect: true,
1580
+ validator: validateEscalationOrder,
1581
+ });
1582
+ }
1583
+ /** The signed-in teammate's own quiet hours (FXO-2103); never another person's. */
1584
+ async getOwnQuietHours(projectId, environmentId, options = {}) {
1585
+ const operation = "getOwnQuietHours";
1586
+ return this.#request({
1587
+ method: "GET",
1588
+ operation,
1589
+ options,
1590
+ path: `${environmentRoot(operation, projectId, environmentId)}/notification-preferences/quiet-hours`,
1591
+ sideEffect: false,
1592
+ validator: validateQuietHours,
1593
+ });
1594
+ }
1595
+ /**
1596
+ * Replaces the signed-in teammate's own quiet hours. A value outside the
1597
+ * rules fails with `request_invalid` naming the field.
1598
+ */
1599
+ async saveOwnQuietHours(projectId, environmentId, request, options = {}) {
1600
+ const operation = "saveOwnQuietHours";
1601
+ assertInput(operation, request, validateSaveQuietHoursRequest);
1602
+ return this.#request({
1603
+ body: request,
1604
+ method: "PUT",
1605
+ operation,
1606
+ options,
1607
+ path: `${environmentRoot(operation, projectId, environmentId)}/notification-preferences/quiet-hours`,
1608
+ sideEffect: true,
1609
+ validator: validateQuietHours,
1610
+ });
1611
+ }
1612
+ /** Turns off the signed-in teammate's own quiet hours. */
1613
+ async resetOwnQuietHours(projectId, environmentId, options = {}) {
1614
+ const operation = "resetOwnQuietHours";
1615
+ return this.#request({
1616
+ method: "DELETE",
1617
+ operation,
1618
+ options,
1619
+ path: `${environmentRoot(operation, projectId, environmentId)}/notification-preferences/quiet-hours`,
1620
+ sideEffect: true,
1621
+ validator: validateQuietHours,
1622
+ });
1623
+ }
1435
1624
  async getEnvironmentRecipientExperience(projectId, environmentId, options = {}) {
1436
1625
  const operation = "getEnvironmentRecipientExperience";
1437
1626
  return this.#request({
@@ -1468,6 +1657,37 @@ export class WhooshBangClient {
1468
1657
  strictResponse: true,
1469
1658
  });
1470
1659
  }
1660
+ /**
1661
+ * One subscriber's escalation order for every urgency, read only. Only the
1662
+ * subscriber can change it, through their recipient session; unlike the
1663
+ * preferred binding, no application credential can set it.
1664
+ */
1665
+ async getSubscriberEscalationOrders(projectId, environmentId, subscriberId, options = {}) {
1666
+ const operation = "getSubscriberEscalationOrders";
1667
+ return this.#request({
1668
+ method: "GET",
1669
+ operation,
1670
+ options,
1671
+ sideEffect: false,
1672
+ path: `${environmentRoot(operation, projectId, environmentId)}/subscribers/${pathSegment(operation, subscriberId, "subscriberId")}/escalation-orders`,
1673
+ validator: validateEscalationOrderCollection,
1674
+ });
1675
+ }
1676
+ /**
1677
+ * One subscriber's quiet hours, read only. Only the subscriber can change
1678
+ * them, through their recipient session.
1679
+ */
1680
+ async getSubscriberQuietHours(projectId, environmentId, subscriberId, options = {}) {
1681
+ const operation = "getSubscriberQuietHours";
1682
+ return this.#request({
1683
+ method: "GET",
1684
+ operation,
1685
+ options,
1686
+ sideEffect: false,
1687
+ path: `${environmentRoot(operation, projectId, environmentId)}/subscribers/${pathSegment(operation, subscriberId, "subscriberId")}/quiet-hours`,
1688
+ validator: validateQuietHours,
1689
+ });
1690
+ }
1471
1691
  async transitionSubscriberBinding(projectId, environmentId, subscriberId, bindingId, action, options = {}) {
1472
1692
  const operation = "transitionSubscriberBinding";
1473
1693
  if (!["pause", "resume", "unsubscribe"].includes(action)) {
@@ -2073,6 +2293,71 @@ export class WhooshBangClient {
2073
2293
  }
2074
2294
  throw new WhooshBangContractError(operation, [cancellationEffectiveMissing("cancelMessage")], "The cancellation response did not say whether cancellation took effect.");
2075
2295
  }
2296
+ /**
2297
+ * Reads an escalation: every stage, each person's attempts and timing, and
2298
+ * the single request-level outcome once it closes.
2299
+ *
2300
+ * While the escalation is open, `wait` holds the read until it closes, up to
2301
+ * 30 seconds; a wait that expires still resolves with the current state.
2302
+ * Inspection changes nothing.
2303
+ */
2304
+ async getEscalation(escalationId, options = {}) {
2305
+ const operation = "getEscalation";
2306
+ const suffix = inspectionWait(operation, options.wait);
2307
+ return this.#request({
2308
+ method: "GET",
2309
+ operation,
2310
+ options,
2311
+ path: `v1/escalations/${pathSegment(operation, escalationId, "escalationId")}${suffix}`,
2312
+ sideEffect: false,
2313
+ validator: validateEscalation,
2314
+ });
2315
+ }
2316
+ /**
2317
+ * Stops every future attempt of an escalation and reports whether this call
2318
+ * closed it.
2319
+ *
2320
+ * Idempotent on the service: cancelling a closed escalation, including one
2321
+ * already answered, returns it unchanged as `already_closed`. Pass
2322
+ * `reason: "resolved"` when your application resolved the matter itself.
2323
+ */
2324
+ async cancelEscalation(escalationId, request = {}, options = {}) {
2325
+ const operation = "cancelEscalation";
2326
+ assertInput(operation, request, validateCancelEscalationRequest);
2327
+ const escalation = await this.#request({
2328
+ body: request,
2329
+ method: "POST",
2330
+ operation,
2331
+ options,
2332
+ path: `v1/escalations/${pathSegment(operation, escalationId, "escalationId")}/cancel`,
2333
+ sideEffect: true,
2334
+ validator: validateEscalation,
2335
+ });
2336
+ return escalationCancelOutcome(operation, escalation);
2337
+ }
2338
+ /**
2339
+ * Cancels the escalation created by the send that used this idempotency
2340
+ * key, for a caller that kept the key but not the escalation id.
2341
+ *
2342
+ * `send_operation` names the send that used the key: `createMessage` (the
2343
+ * default, covering `createMessageInEnvironment` too) or
2344
+ * `sendOperatorMessage`. A key whose send did not escalate, or that matches
2345
+ * nothing, is `resource_not_found`.
2346
+ */
2347
+ async cancelEscalationByKey(request, options = {}) {
2348
+ const operation = "cancelEscalationByKey";
2349
+ assertInput(operation, request, validateCancelEscalationByKeyRequest);
2350
+ const escalation = await this.#request({
2351
+ body: request,
2352
+ method: "POST",
2353
+ operation,
2354
+ options,
2355
+ path: "v1/escalations/cancel",
2356
+ sideEffect: true,
2357
+ validator: validateEscalation,
2358
+ });
2359
+ return escalationCancelOutcome(operation, escalation);
2360
+ }
2076
2361
  async getCapabilities(options = {}) {
2077
2362
  return this.#request({
2078
2363
  method: "GET",
@@ -2953,6 +3238,161 @@ export class WhooshBangClient {
2953
3238
  validator: validateInteractionSummary,
2954
3239
  });
2955
3240
  }
3241
+ async getEscalationInEnvironment(projectId, environmentId, escalationId, options = {}) {
3242
+ const operation = "getEscalationInEnvironment";
3243
+ const suffix = inspectionWait(operation, options.wait);
3244
+ return this.#request({
3245
+ method: "GET",
3246
+ operation,
3247
+ options,
3248
+ path: `${environmentRoot(operation, projectId, environmentId)}/escalations/` +
3249
+ `${pathSegment(operation, escalationId, "escalationId")}${suffix}`,
3250
+ sideEffect: false,
3251
+ validator: validateEscalation,
3252
+ });
3253
+ }
3254
+ async cancelEscalationInEnvironment(projectId, environmentId, escalationId, request = {}, options = {}) {
3255
+ const operation = "cancelEscalationInEnvironment";
3256
+ assertInput(operation, request, validateCancelEscalationRequest);
3257
+ const escalation = await this.#request({
3258
+ body: request,
3259
+ method: "POST",
3260
+ operation,
3261
+ options,
3262
+ path: `${environmentRoot(operation, projectId, environmentId)}/escalations/` +
3263
+ `${pathSegment(operation, escalationId, "escalationId")}/cancel`,
3264
+ sideEffect: true,
3265
+ validator: validateEscalation,
3266
+ });
3267
+ return escalationCancelOutcome(operation, escalation);
3268
+ }
3269
+ async cancelEscalationByKeyInEnvironment(projectId, environmentId, request, options = {}) {
3270
+ const operation = "cancelEscalationByKeyInEnvironment";
3271
+ assertInput(operation, request, validateCancelEscalationByKeyRequest);
3272
+ const escalation = await this.#request({
3273
+ body: request,
3274
+ method: "POST",
3275
+ operation,
3276
+ options,
3277
+ path: `${environmentRoot(operation, projectId, environmentId)}/escalations/cancel`,
3278
+ sideEffect: true,
3279
+ validator: validateEscalation,
3280
+ });
3281
+ return escalationCancelOutcome(operation, escalation);
3282
+ }
3283
+ /**
3284
+ * The environment's escalation limits and the most each may be
3285
+ * (FXO-2105). Until someone narrows them every limit is its maximum and
3286
+ * `version` is absent.
3287
+ */
3288
+ async getEscalationLimits(projectId, environmentId, options = {}) {
3289
+ const operation = "getEscalationLimits";
3290
+ return this.#request({
3291
+ method: "GET",
3292
+ operation,
3293
+ options,
3294
+ path: `${environmentRoot(operation, projectId, environmentId)}/escalation-limits`,
3295
+ sideEffect: false,
3296
+ validator: validateEscalationLimits,
3297
+ });
3298
+ }
3299
+ /**
3300
+ * Narrows the environment's escalation limits. Send the `version` read,
3301
+ * or omit it when none was shown; a stale one fails with
3302
+ * `escalation_limits_conflict` and nothing changes.
3303
+ */
3304
+ async updateEscalationLimits(projectId, environmentId, request, options = {}) {
3305
+ const operation = "updateEscalationLimits";
3306
+ assertInput(operation, request, validateUpdateEscalationLimitsRequest);
3307
+ return this.#request({
3308
+ body: request,
3309
+ method: "PUT",
3310
+ operation,
3311
+ options,
3312
+ path: `${environmentRoot(operation, projectId, environmentId)}/escalation-limits`,
3313
+ sideEffect: true,
3314
+ validator: validateEscalationLimits,
3315
+ });
3316
+ }
3317
+ /** What the paging limit held back in this environment over the last 7 days. */
3318
+ async getEscalationPagingLimitReport(projectId, environmentId, options = {}) {
3319
+ const operation = "getEscalationPagingLimitReport";
3320
+ return this.#request({
3321
+ method: "GET",
3322
+ operation,
3323
+ options,
3324
+ path: `${environmentRoot(operation, projectId, environmentId)}/escalation-limits/held-back`,
3325
+ sideEffect: false,
3326
+ validator: validateEscalationPagingLimitReport,
3327
+ });
3328
+ }
3329
+ /** One escalation default per urgency tier, lowest first (FXO-2103). */
3330
+ async listEscalationPolicies(projectId, environmentId, options = {}) {
3331
+ const operation = "listEscalationPolicies";
3332
+ return this.#request({
3333
+ method: "GET",
3334
+ operation,
3335
+ options,
3336
+ path: `${environmentRoot(operation, projectId, environmentId)}/escalation-policies`,
3337
+ sideEffect: false,
3338
+ validator: validateEscalationPolicyCollection,
3339
+ });
3340
+ }
3341
+ /** A tier's saved default, or the built-in suggested order. */
3342
+ async getEscalationPolicy(projectId, environmentId, level, options = {}) {
3343
+ const operation = "getEscalationPolicy";
3344
+ return this.#request({
3345
+ method: "GET",
3346
+ operation,
3347
+ options,
3348
+ path: `${environmentRoot(operation, projectId, environmentId)}/escalation-policies/${pathSegment(operation, level, "level")}`,
3349
+ sideEffect: false,
3350
+ validator: validateEscalationPolicy,
3351
+ });
3352
+ }
3353
+ /**
3354
+ * Saves a tier's default as a new version. Every step's channel must be
3355
+ * connected in the environment, or the call fails with
3356
+ * `escalation_policy_channel_unconnected` and nothing changes.
3357
+ */
3358
+ async updateEscalationPolicy(projectId, environmentId, level, request, options = {}) {
3359
+ const operation = "updateEscalationPolicy";
3360
+ assertInput(operation, request, validateUpdateEscalationPolicyRequest);
3361
+ return this.#request({
3362
+ body: request,
3363
+ method: "PUT",
3364
+ operation,
3365
+ options,
3366
+ path: `${environmentRoot(operation, projectId, environmentId)}/escalation-policies/${pathSegment(operation, level, "level")}`,
3367
+ sideEffect: true,
3368
+ validator: validateEscalationPolicy,
3369
+ });
3370
+ }
3371
+ /** Returns a tier to the built-in suggested order and returns that order. */
3372
+ async resetEscalationPolicy(projectId, environmentId, level, options = {}) {
3373
+ const operation = "resetEscalationPolicy";
3374
+ return this.#request({
3375
+ method: "DELETE",
3376
+ operation,
3377
+ options,
3378
+ path: `${environmentRoot(operation, projectId, environmentId)}/escalation-policies/${pathSegment(operation, level, "level")}`,
3379
+ sideEffect: true,
3380
+ validator: validateEscalationPolicy,
3381
+ });
3382
+ }
3383
+ /** The order an escalation at this tier would snapshot for one subscriber. */
3384
+ async previewEscalationPath(projectId, environmentId, level, subscriberId, options = {}) {
3385
+ const operation = "previewEscalationPath";
3386
+ const query = new URLSearchParams({ subscriber_id: subscriberId });
3387
+ return this.#request({
3388
+ method: "GET",
3389
+ operation,
3390
+ options,
3391
+ path: `${environmentRoot(operation, projectId, environmentId)}/escalation-policies/${pathSegment(operation, level, "level")}/preview?${query}`,
3392
+ sideEffect: false,
3393
+ validator: validateEscalationPathPreview,
3394
+ });
3395
+ }
2956
3396
  async createMachineClientInEnvironment(projectId, environmentId, request, options = {}) {
2957
3397
  const operation = "createMachineClientInEnvironment";
2958
3398
  assertInput(operation, request, validateCreateMachineClientRequest);
@@ -3546,6 +3986,101 @@ export class WhooshBangRecipientSessionClient {
3546
3986
  validator: validatePreferredBinding,
3547
3987
  });
3548
3988
  }
3989
+ /**
3990
+ * This subscriber's escalation order for every urgency: their own where they
3991
+ * saved one, otherwise the project's, with each step's availability and the
3992
+ * eligible bindings the order leaves out.
3993
+ */
3994
+ async getEscalationOrders(options = {}) {
3995
+ const operation = "getEscalationOrders";
3996
+ return this.#request({
3997
+ method: "GET",
3998
+ operation,
3999
+ options,
4000
+ path: "v1/recipient-session/escalation-orders",
4001
+ sideEffect: false,
4002
+ validator: validateEscalationOrderCollection,
4003
+ });
4004
+ }
4005
+ /**
4006
+ * Saves this subscriber's own order for one urgency. An empty `steps` is a
4007
+ * choice that nothing is tried. Send back the `version` the tier showed
4008
+ * when read (none for the suggested order); an order that changed since
4009
+ * fails with `escalation_order_conflict`, and a binding they cannot use
4010
+ * with `escalation_order_step_ineligible`.
4011
+ */
4012
+ async saveEscalationOrder(level, request, options = {}) {
4013
+ const operation = "saveEscalationOrder";
4014
+ assertInput(operation, request, validateSaveEscalationOrderRequest);
4015
+ return this.#request({
4016
+ body: request,
4017
+ method: "PUT",
4018
+ operation,
4019
+ options,
4020
+ path: `v1/recipient-session/escalation-orders/${pathSegment(operation, level, "level")}`,
4021
+ sideEffect: true,
4022
+ validator: validateEscalationOrder,
4023
+ });
4024
+ }
4025
+ /** Goes back to the project's order for one urgency. */
4026
+ async resetEscalationOrder(level, options = {}) {
4027
+ const operation = "resetEscalationOrder";
4028
+ return this.#request({
4029
+ method: "DELETE",
4030
+ operation,
4031
+ options,
4032
+ path: `v1/recipient-session/escalation-orders/${pathSegment(operation, level, "level")}`,
4033
+ sideEffect: true,
4034
+ validator: validateEscalationOrder,
4035
+ });
4036
+ }
4037
+ /**
4038
+ * This subscriber's quiet hours: when they would rather not be interrupted,
4039
+ * what each channel does then, the choices each channel offers, the
4040
+ * channels a withheld message can go to, and whether quiet hours are on now.
4041
+ */
4042
+ async getQuietHours(options = {}) {
4043
+ const operation = "getQuietHours";
4044
+ return this.#request({
4045
+ method: "GET",
4046
+ operation,
4047
+ options,
4048
+ path: "v1/recipient-session/quiet-hours",
4049
+ sideEffect: false,
4050
+ validator: validateQuietHours,
4051
+ });
4052
+ }
4053
+ /**
4054
+ * Replaces this subscriber's quiet hours. Send the time zone they see the
4055
+ * times in. A value outside the rules fails with `request_invalid` naming
4056
+ * the field, such as `quiet_channel_unavailable` for a quiet channel that
4057
+ * is not theirs.
4058
+ */
4059
+ async saveQuietHours(request, options = {}) {
4060
+ const operation = "saveQuietHours";
4061
+ assertInput(operation, request, validateSaveQuietHoursRequest);
4062
+ return this.#request({
4063
+ body: request,
4064
+ method: "PUT",
4065
+ operation,
4066
+ options,
4067
+ path: "v1/recipient-session/quiet-hours",
4068
+ sideEffect: true,
4069
+ validator: validateQuietHours,
4070
+ });
4071
+ }
4072
+ /** Turns off this subscriber's quiet hours. */
4073
+ async resetQuietHours(options = {}) {
4074
+ const operation = "resetQuietHours";
4075
+ return this.#request({
4076
+ method: "DELETE",
4077
+ operation,
4078
+ options,
4079
+ path: "v1/recipient-session/quiet-hours",
4080
+ sideEffect: true,
4081
+ validator: validateQuietHours,
4082
+ });
4083
+ }
3549
4084
  async transitionBinding(bindingId, action, options = {}) {
3550
4085
  const operation = `${action}RecipientBinding`;
3551
4086
  return this.#request({