From 166f09d23f53cda5b63b60a9a785bc9e2e430fb7 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 18:04:43 +0000
Subject: [PATCH 01/33] chore: sync repo
---
.devcontainer/Dockerfile | 23 +
.devcontainer/devcontainer.json | 20 +
.fernignore | 4 -
.gitattributes | 5 +
.github/workflows/ci.yml | 110 +-
.gitignore | 29 +-
.publish/prepare.sh | 8 -
.stats.yml | 4 +
LICENSE | 222 +-
README.md | 698 +-
SECURITY.md | 23 +
build.gradle | 88 -
build.gradle.kts | 49 +
buildSrc/build.gradle.kts | 12 +
.../src/main/kotlin/courier.java.gradle.kts | 136 +
.../src/main/kotlin/courier.kotlin.gradle.kts | 106 +
.../main/kotlin/courier.publish.gradle.kts | 60 +
courier-java-client-okhttp/build.gradle.kts | 14 +
.../api/client/okhttp/CourierOkHttpClient.kt | 307 +
.../client/okhttp/CourierOkHttpClientAsync.kt | 307 +
.../courier/api/client/okhttp/OkHttpClient.kt | 246 +
courier-java-core/build.gradle.kts | 41 +
.../com/courier/api/client/CourierClient.kt | 147 +
.../courier/api/client/CourierClientAsync.kt | 151 +
.../api/client/CourierClientAsyncImpl.kt | 259 +
.../courier/api/client/CourierClientImpl.kt | 247 +
.../com/courier/api/core/BaseDeserializer.kt | 44 +
.../com/courier/api/core/BaseSerializer.kt | 6 +
.../main/kotlin/com/courier/api/core/Check.kt | 96 +
.../com/courier/api/core/ClientOptions.kt | 450 +
.../com/courier/api/core/DefaultSleeper.kt | 28 +
.../com/courier/api/core/ObjectMappers.kt | 167 +
.../kotlin/com/courier/api/core/Params.kt | 16 +
.../com/courier/api/core/PhantomReachable.kt | 56 +
.../core/PhantomReachableExecutorService.kt | 58 +
.../api/core/PhantomReachableSleeper.kt | 23 +
.../com/courier/api/core/PrepareRequest.kt | 24 +
.../kotlin/com/courier/api/core/Properties.kt | 42 +
.../com/courier/api/core/RequestOptions.kt | 46 +
.../kotlin/com/courier/api/core/Sleeper.kt | 21 +
.../kotlin/com/courier/api/core/Timeout.kt | 171 +
.../main/kotlin/com/courier/api/core/Utils.kt | 115 +
.../kotlin/com/courier/api/core/Values.kt | 723 ++
.../courier/api/core/handlers/EmptyHandler.kt | 12 +
.../courier/api/core/handlers/ErrorHandler.kt | 84 +
.../courier/api/core/handlers/JsonHandler.kt | 20 +
.../api/core/handlers/StringHandler.kt | 13 +
.../api/core/http/AsyncStreamResponse.kt | 157 +
.../com/courier/api/core/http/Headers.kt | 115 +
.../com/courier/api/core/http/HttpClient.kt | 26 +
.../com/courier/api/core/http/HttpMethod.kt | 13 +
.../com/courier/api/core/http/HttpRequest.kt | 146 +
.../api/core/http/HttpRequestBodies.kt | 128 +
.../courier/api/core/http/HttpRequestBody.kt | 25 +
.../com/courier/api/core/http/HttpResponse.kt | 22 +
.../courier/api/core/http/HttpResponseFor.kt | 25 +
...ntomReachableClosingAsyncStreamResponse.kt | 56 +
.../http/PhantomReachableClosingHttpClient.kt | 26 +
.../PhantomReachableClosingStreamResponse.kt | 21 +
.../com/courier/api/core/http/QueryParams.kt | 129 +
.../api/core/http/RetryingHttpClient.kt | 265 +
.../courier/api/core/http/StreamResponse.kt | 19 +
.../courier/api/errors/BadRequestException.kt | 80 +
.../courier/api/errors/CourierException.kt | 5 +
.../api/errors/CourierInvalidDataException.kt | 5 +
.../courier/api/errors/CourierIoException.kt | 5 +
.../api/errors/CourierRetryableException.kt | 14 +
.../api/errors/CourierServiceException.kt | 17 +
.../api/errors/InternalServerException.kt | 91 +
.../courier/api/errors/NotFoundException.kt | 76 +
.../api/errors/PermissionDeniedException.kt | 80 +
.../courier/api/errors/RateLimitException.kt | 80 +
.../api/errors/UnauthorizedException.kt | 80 +
.../errors/UnexpectedStatusCodeException.kt | 92 +
.../errors/UnprocessableEntityException.kt | 80 +
.../courier/api/models/audiences/Audience.kt | 364 +
.../models/audiences/AudienceDeleteParams.kt | 229 +
.../audiences/AudienceListMembersParams.kt | 216 +
.../audiences/AudienceListMembersResponse.kt | 538 +
.../models/audiences/AudienceListParams.kt | 191 +
.../models/audiences/AudienceListResponse.kt | 221 +
.../audiences/AudienceRetrieveParams.kt | 194 +
.../models/audiences/AudienceUpdateParams.kt | 577 +
.../audiences/AudienceUpdateResponse.kt | 172 +
.../courier/api/models/audiences/Filter.kt | 660 ++
.../api/models/audiences/FilterConfig.kt | 656 ++
.../models/audiences/NestedFilterConfig.kt | 439 +
.../courier/api/models/audiences/Paging.kt | 203 +
.../api/models/auditevents/AuditEvent.kt | 703 ++
.../auditevents/AuditEventListParams.kt | 191 +
.../auditevents/AuditEventListResponse.kt | 226 +
.../auditevents/AuditEventRetrieveParams.kt | 194 +
.../api/models/auth/AuthIssueTokenParams.kt | 676 ++
.../api/models/auth/AuthIssueTokenResponse.kt | 157 +
.../AutomationInvokeAdHocParams.kt | 9460 +++++++++++++++++
.../AutomationInvokeByTemplateParams.kt | 228 +
.../invoke/AutomationInvokeParams.kt | 377 +
.../invoke/AutomationInvokeResponse.kt | 170 +
.../automations/invoke/AutomationStep.kt | 190 +
.../automations/invoke/MergeAlgorithm.kt | 144 +
.../com/courier/api/models/brands/Brand.kt | 452 +
.../api/models/brands/BrandCreateParams.kt | 618 ++
.../api/models/brands/BrandDeleteParams.kt | 229 +
.../api/models/brands/BrandListParams.kt | 191 +
.../api/models/brands/BrandListResponse.kt | 224 +
.../api/models/brands/BrandRetrieveParams.kt | 189 +
.../api/models/brands/BrandSettings.kt | 565 +
.../api/models/brands/BrandSnippets.kt | 540 +
.../api/models/brands/BrandUpdateParams.kt | 577 +
.../api/models/bulk/BulkAddUsersParams.kt | 462 +
.../api/models/bulk/BulkCreateJobParams.kt | 416 +
.../api/models/bulk/BulkCreateJobResponse.kt | 170 +
.../api/models/bulk/BulkListUsersParams.kt | 216 +
.../api/models/bulk/BulkListUsersResponse.kt | 710 ++
.../api/models/bulk/BulkRetrieveJobParams.kt | 189 +
.../models/bulk/BulkRetrieveJobResponse.kt | 612 ++
.../api/models/bulk/BulkRunJobParams.kt | 229 +
.../api/models/bulk/InboundBulkMessage.kt | 2294 ++++
.../api/models/bulk/InboundBulkMessageUser.kt | 264 +
.../courier/api/models/bulk/UserRecipient.kt | 1046 ++
.../models/inbound/InboundTrackEventParams.kt | 925 ++
.../inbound/InboundTrackEventResponse.kt | 177 +
.../com/courier/api/models/lists/List.kt | 291 +
.../api/models/lists/ListDeleteParams.kt | 229 +
.../api/models/lists/ListListParams.kt | 220 +
.../api/models/lists/ListListResponse.kt | 222 +
.../api/models/lists/ListRestoreParams.kt | 229 +
.../api/models/lists/ListRetrieveParams.kt | 189 +
.../api/models/lists/ListUpdateParams.kt | 508 +
.../PutSubscriptionsRecipient.kt | 222 +
.../subscriptions/RecipientPreferences.kt | 407 +
.../subscriptions/SubscriptionAddParams.kt | 473 +
.../subscriptions/SubscriptionListParams.kt | 214 +
.../subscriptions/SubscriptionListResponse.kt | 467 +
.../SubscriptionSubscribeParams.kt | 473 +
.../SubscriptionSubscribeUserParams.kt | 452 +
.../SubscriptionUnsubscribeUserParams.kt | 262 +
.../models/messages/MessageCancelParams.kt | 234 +
.../api/models/messages/MessageDetails.kt | 991 ++
.../messages/MessageGetContentParams.kt | 193 +
.../messages/MessageGetContentResponse.kt | 1015 ++
.../models/messages/MessageHistoryParams.kt | 214 +
.../models/messages/MessageHistoryResponse.kt | 289 +
.../api/models/messages/MessageListParams.kt | 475 +
.../models/messages/MessageListResponse.kt | 234 +
.../models/messages/MessageRetrieveParams.kt | 193 +
.../messages/MessageRetrieveResponse.kt | 814 ++
.../models/notifications/MessageRouting.kt | 363 +
.../notifications/MessageRoutingChannel.kt | 196 +
.../notifications/NotificationGetContent.kt | 1906 ++++
.../notifications/NotificationListParams.kt | 215 +
.../notifications/NotificationListResponse.kt | 1014 ++
.../NotificationRetrieveContentParams.kt | 197 +
.../models/notifications/checks/BaseCheck.kt | 490 +
.../api/models/notifications/checks/Check.kt | 280 +
.../notifications/checks/CheckDeleteParams.kt | 257 +
.../notifications/checks/CheckListParams.kt | 216 +
.../notifications/checks/CheckListResponse.kt | 190 +
.../notifications/checks/CheckUpdateParams.kt | 471 +
.../checks/CheckUpdateResponse.kt | 190 +
.../draft/DraftRetrieveContentParams.kt | 190 +
.../models/profiles/ProfileCreateParams.kt | 534 +
.../models/profiles/ProfileCreateResponse.kt | 291 +
.../models/profiles/ProfileDeleteParams.kt | 229 +
.../models/profiles/ProfileReplaceParams.kt | 536 +
.../models/profiles/ProfileReplaceResponse.kt | 291 +
.../models/profiles/ProfileRetrieveParams.kt | 189 +
.../profiles/ProfileRetrieveResponse.kt | 318 +
.../models/profiles/ProfileUpdateParams.kt | 699 ++
.../models/profiles/lists/ListDeleteParams.kt | 229 +
.../profiles/lists/ListDeleteResponse.kt | 288 +
.../profiles/lists/ListRetrieveParams.kt | 214 +
.../profiles/lists/ListRetrieveResponse.kt | 547 +
.../profiles/lists/ListSubscribeParams.kt | 664 ++
.../profiles/lists/ListSubscribeResponse.kt | 291 +
.../models/requests/RequestArchiveParams.kt | 229 +
.../courier/api/models/send/BaseMessage.kt | 4181 ++++++++
.../api/models/send/BaseMessageSendTo.kt | 7483 +++++++++++++
.../com/courier/api/models/send/Content.kt | 671 ++
.../api/models/send/ElementalChannelNode.kt | 572 +
.../api/models/send/ElementalGroupNode.kt | 385 +
.../courier/api/models/send/ElementalNode.kt | 4182 ++++++++
.../com/courier/api/models/send/Message.kt | 1873 ++++
.../courier/api/models/send/MessageContext.kt | 165 +
.../api/models/send/MsTeamsBaseProperties.kt | 208 +
.../com/courier/api/models/send/Recipient.kt | 7064 ++++++++++++
.../courier/api/models/send/RoutingMethod.kt | 132 +
.../api/models/send/SendSendMessageParams.kt | 429 +
.../models/send/SendSendMessageResponse.kt | 194 +
.../api/models/send/SlackBaseProperties.kt | 175 +
.../kotlin/com/courier/api/models/send/Utm.kt | 293 +
.../api/models/tenants/DefaultPreferences.kt | 512 +
.../com/courier/api/models/tenants/Tenant.kt | 655 ++
.../api/models/tenants/TenantDeleteParams.kt | 229 +
.../api/models/tenants/TenantListParams.kt | 234 +
.../api/models/tenants/TenantListResponse.kt | 501 +
.../models/tenants/TenantListUsersParams.kt | 236 +
.../models/tenants/TenantListUsersResponse.kt | 502 +
.../models/tenants/TenantRetrieveParams.kt | 189 +
.../api/models/tenants/TenantUpdateParams.kt | 1055 ++
.../items/ChannelClassification.kt | 158 +
.../items/ItemDeleteParams.kt | 258 +
.../items/ItemUpdateParams.kt | 242 +
.../items/SubscriptionTopicNew.kt | 428 +
.../translations/TranslationRetrieveParams.kt | 217 +
.../translations/TranslationUpdateParams.kt | 230 +
.../preferences/PreferenceRetrieveParams.kt | 214 +
.../preferences/PreferenceRetrieveResponse.kt | 230 +
.../PreferenceRetrieveTopicParams.kt | 238 +
.../PreferenceRetrieveTopicResponse.kt | 175 +
.../users/preferences/PreferenceStatus.kt | 139 +
.../PreferenceUpdateOrCreateTopicParams.kt | 745 ++
.../PreferenceUpdateOrCreateTopicResponse.kt | 174 +
.../users/preferences/TopicPreference.kt | 417 +
.../users/tenants/TenantAddMultipleParams.kt | 467 +
.../users/tenants/TenantAddSingleParams.kt | 537 +
.../models/users/tenants/TenantAssociation.kt | 508 +
.../models/users/tenants/TenantListParams.kt | 236 +
.../users/tenants/TenantListResponse.kt | 501 +
.../users/tenants/TenantRemoveAllParams.kt | 229 +
.../users/tenants/TenantRemoveSingleParams.kt | 259 +
.../users/tokens/TokenAddMultipleParams.kt | 230 +
.../users/tokens/TokenAddSingleParams.kt | 233 +
.../models/users/tokens/TokenDeleteParams.kt | 258 +
.../models/users/tokens/TokenListParams.kt | 189 +
.../users/tokens/TokenRetrieveSingleParams.kt | 217 +
.../tokens/TokenRetrieveSingleResponse.kt | 616 ++
.../models/users/tokens/TokenUpdateParams.kt | 706 ++
.../api/models/users/tokens/UserToken.kt | 1309 +++
.../services/async/AudienceServiceAsync.kt | 389 +
.../async/AudienceServiceAsyncImpl.kt | 250 +
.../services/async/AuditEventServiceAsync.kt | 162 +
.../async/AuditEventServiceAsyncImpl.kt | 128 +
.../api/services/async/AuthServiceAsync.kt | 62 +
.../services/async/AuthServiceAsyncImpl.kt | 86 +
.../services/async/AutomationServiceAsync.kt | 134 +
.../async/AutomationServiceAsyncImpl.kt | 142 +
.../api/services/async/BrandServiceAsync.kt | 302 +
.../services/async/BrandServiceAsyncImpl.kt | 243 +
.../api/services/async/BulkServiceAsync.kt | 335 +
.../services/async/BulkServiceAsyncImpl.kt | 243 +
.../api/services/async/InboundServiceAsync.kt | 66 +
.../services/async/InboundServiceAsyncImpl.kt | 86 +
.../api/services/async/ListServiceAsync.kt | 344 +
.../services/async/ListServiceAsyncImpl.kt | 254 +
.../api/services/async/MessageServiceAsync.kt | 407 +
.../services/async/MessageServiceAsyncImpl.kt | 256 +
.../async/NotificationServiceAsync.kt | 175 +
.../async/NotificationServiceAsyncImpl.kt | 152 +
.../api/services/async/ProfileServiceAsync.kt | 361 +
.../services/async/ProfileServiceAsyncImpl.kt | 259 +
.../api/services/async/RequestServiceAsync.kt | 110 +
.../services/async/RequestServiceAsyncImpl.kt | 82 +
.../api/services/async/SendServiceAsync.kt | 62 +
.../services/async/SendServiceAsyncImpl.kt | 86 +
.../api/services/async/TenantServiceAsync.kt | 366 +
.../services/async/TenantServiceAsyncImpl.kt | 262 +
.../services/async/TranslationServiceAsync.kt | 142 +
.../async/TranslationServiceAsyncImpl.kt | 118 +
.../api/services/async/UserServiceAsync.kt | 47 +
.../services/async/UserServiceAsyncImpl.kt | 68 +
.../async/automations/InvokeServiceAsync.kt | 36 +
.../automations/InvokeServiceAsyncImpl.kt | 30 +
.../async/lists/SubscriptionServiceAsync.kt | 331 +
.../lists/SubscriptionServiceAsyncImpl.kt | 241 +
.../async/notifications/CheckServiceAsync.kt | 193 +
.../notifications/CheckServiceAsyncImpl.kt | 184 +
.../async/notifications/DraftServiceAsync.kt | 118 +
.../notifications/DraftServiceAsyncImpl.kt | 89 +
.../async/profiles/ListServiceAsync.kt | 250 +
.../async/profiles/ListServiceAsyncImpl.kt | 176 +
.../tenants/DefaultPreferenceServiceAsync.kt | 42 +
.../DefaultPreferenceServiceAsyncImpl.kt | 44 +
.../defaultpreferences/ItemServiceAsync.kt | 133 +
.../ItemServiceAsyncImpl.kt | 129 +
.../async/users/PreferenceServiceAsync.kt | 239 +
.../async/users/PreferenceServiceAsyncImpl.kt | 185 +
.../async/users/TenantServiceAsync.kt | 345 +
.../async/users/TenantServiceAsyncImpl.kt | 231 +
.../services/async/users/TokenServiceAsync.kt | 385 +
.../async/users/TokenServiceAsyncImpl.kt | 273 +
.../api/services/blocking/AudienceService.kt | 382 +
.../services/blocking/AudienceServiceImpl.kt | 232 +
.../services/blocking/AuditEventService.kt | 158 +
.../blocking/AuditEventServiceImpl.kt | 121 +
.../api/services/blocking/AuthService.kt | 62 +
.../api/services/blocking/AuthServiceImpl.kt | 81 +
.../services/blocking/AutomationService.kt | 133 +
.../blocking/AutomationServiceImpl.kt | 135 +
.../api/services/blocking/BrandService.kt | 287 +
.../api/services/blocking/BrandServiceImpl.kt | 213 +
.../api/services/blocking/BulkService.kt | 328 +
.../api/services/blocking/BulkServiceImpl.kt | 222 +
.../api/services/blocking/InboundService.kt | 63 +
.../services/blocking/InboundServiceImpl.kt | 82 +
.../api/services/blocking/ListService.kt | 330 +
.../api/services/blocking/ListServiceImpl.kt | 224 +
.../api/services/blocking/MessageService.kt | 397 +
.../services/blocking/MessageServiceImpl.kt | 240 +
.../services/blocking/NotificationService.kt | 171 +
.../blocking/NotificationServiceImpl.kt | 145 +
.../api/services/blocking/ProfileService.kt | 346 +
.../services/blocking/ProfileServiceImpl.kt | 239 +
.../api/services/blocking/RequestService.kt | 103 +
.../services/blocking/RequestServiceImpl.kt | 76 +
.../api/services/blocking/SendService.kt | 62 +
.../api/services/blocking/SendServiceImpl.kt | 81 +
.../api/services/blocking/TenantService.kt | 349 +
.../services/blocking/TenantServiceImpl.kt | 238 +
.../services/blocking/TranslationService.kt | 140 +
.../blocking/TranslationServiceImpl.kt | 109 +
.../api/services/blocking/UserService.kt | 47 +
.../api/services/blocking/UserServiceImpl.kt | 65 +
.../blocking/automations/InvokeService.kt | 32 +
.../blocking/automations/InvokeServiceImpl.kt | 30 +
.../blocking/lists/SubscriptionService.kt | 321 +
.../blocking/lists/SubscriptionServiceImpl.kt | 223 +
.../blocking/notifications/CheckService.kt | 189 +
.../notifications/CheckServiceImpl.kt | 169 +
.../blocking/notifications/DraftService.kt | 113 +
.../notifications/DraftServiceImpl.kt | 85 +
.../services/blocking/profiles/ListService.kt | 243 +
.../blocking/profiles/ListServiceImpl.kt | 165 +
.../tenants/DefaultPreferenceService.kt | 42 +
.../tenants/DefaultPreferenceServiceImpl.kt | 42 +
.../tenants/defaultpreferences/ItemService.kt | 127 +
.../defaultpreferences/ItemServiceImpl.kt | 117 +
.../blocking/users/PreferenceService.kt | 239 +
.../blocking/users/PreferenceServiceImpl.kt | 175 +
.../services/blocking/users/TenantService.kt | 336 +
.../blocking/users/TenantServiceImpl.kt | 207 +
.../services/blocking/users/TokenService.kt | 375 +
.../blocking/users/TokenServiceImpl.kt | 243 +
.../META-INF/proguard/courier-java-core.pro | 32 +
.../com/courier/api/TestServerExtension.kt | 62 +
.../com/courier/api/core/ClientOptionsTest.kt | 34 +
.../com/courier/api/core/ObjectMappersTest.kt | 102 +
.../courier/api/core/PhantomReachableTest.kt | 27 +
.../kotlin/com/courier/api/core/UtilsTest.kt | 33 +
.../kotlin/com/courier/api/core/ValuesTest.kt | 144 +
.../api/core/http/AsyncStreamResponseTest.kt | 268 +
.../com/courier/api/core/http/HeadersTest.kt | 242 +
.../courier/api/core/http/QueryParamsTest.kt | 180 +
.../api/core/http/RetryingHttpClientTest.kt | 356 +
.../audiences/AudienceDeleteParamsTest.kt | 23 +
.../AudienceListMembersParamsTest.kt | 43 +
.../AudienceListMembersResponseTest.kt | 67 +
.../audiences/AudienceListParamsTest.kt | 33 +
.../audiences/AudienceListResponseTest.kt | 88 +
.../audiences/AudienceRetrieveParamsTest.kt | 23 +
.../api/models/audiences/AudienceTest.kt | 74 +
.../audiences/AudienceUpdateParamsTest.kt | 73 +
.../audiences/AudienceUpdateResponseTest.kt | 84 +
.../api/models/audiences/FilterConfigTest.kt | 115 +
.../api/models/audiences/FilterTest.kt | 109 +
.../audiences/NestedFilterConfigTest.kt | 62 +
.../api/models/audiences/PagingTest.kt | 30 +
.../auditevents/AuditEventListParamsTest.kt | 33 +
.../auditevents/AuditEventListResponseTest.kt | 71 +
.../AuditEventRetrieveParamsTest.kt | 23 +
.../api/models/auditevents/AuditEventTest.kt | 55 +
.../models/auth/AuthIssueTokenParamsTest.kt | 31 +
.../models/auth/AuthIssueTokenResponseTest.kt | 32 +
.../AutomationInvokeAdHocParamsTest.kt | 156 +
.../AutomationInvokeByTemplateParamsTest.kt | 95 +
.../invoke/AutomationInvokeParamsTest.kt | 65 +
.../invoke/AutomationInvokeResponseTest.kt | 35 +
.../automations/invoke/AutomationStepTest.kt | 33 +
.../models/brands/BrandCreateParamsTest.kt | 135 +
.../models/brands/BrandDeleteParamsTest.kt | 23 +
.../api/models/brands/BrandListParamsTest.kt | 33 +
.../models/brands/BrandListResponseTest.kt | 159 +
.../models/brands/BrandRetrieveParamsTest.kt | 23 +
.../api/models/brands/BrandSettingsTest.kt | 80 +
.../api/models/brands/BrandSnippetsTest.kt | 57 +
.../courier/api/models/brands/BrandTest.kt | 140 +
.../models/brands/BrandUpdateParamsTest.kt | 138 +
.../api/models/bulk/BulkAddUsersParamsTest.kt | 433 +
.../models/bulk/BulkCreateJobParamsTest.kt | 588 +
.../models/bulk/BulkCreateJobResponseTest.kt | 32 +
.../models/bulk/BulkListUsersParamsTest.kt | 42 +
.../models/bulk/BulkListUsersResponseTest.kt | 436 +
.../models/bulk/BulkRetrieveJobParamsTest.kt | 23 +
.../bulk/BulkRetrieveJobResponseTest.kt | 674 ++
.../api/models/bulk/BulkRunJobParamsTest.kt | 23 +
.../api/models/bulk/InboundBulkMessageTest.kt | 555 +
.../models/bulk/InboundBulkMessageUserTest.kt | 369 +
.../api/models/bulk/UserRecipientTest.kt | 201 +
.../inbound/InboundTrackEventParamsTest.kt | 91 +
.../inbound/InboundTrackEventResponseTest.kt | 39 +
.../api/models/lists/ListDeleteParamsTest.kt | 23 +
.../api/models/lists/ListListParamsTest.kt | 36 +
.../api/models/lists/ListListResponseTest.kt | 44 +
.../api/models/lists/ListRestoreParamsTest.kt | 23 +
.../models/lists/ListRetrieveParamsTest.kt | 23 +
.../com/courier/api/models/lists/ListTest.kt | 32 +
.../api/models/lists/ListUpdateParamsTest.kt | 163 +
.../PutSubscriptionsRecipientTest.kt | 156 +
.../subscriptions/RecipientPreferencesTest.kt | 128 +
.../SubscriptionAddParamsTest.kt | 217 +
.../SubscriptionListParamsTest.kt | 42 +
.../SubscriptionListResponseTest.kt | 206 +
.../SubscriptionSubscribeParamsTest.kt | 217 +
.../SubscriptionSubscribeUserParamsTest.kt | 162 +
.../SubscriptionUnsubscribeUserParamsTest.kt | 25 +
.../messages/MessageCancelParamsTest.kt | 23 +
.../api/models/messages/MessageDetailsTest.kt | 71 +
.../messages/MessageGetContentParamsTest.kt | 23 +
.../messages/MessageGetContentResponseTest.kt | 99 +
.../messages/MessageHistoryParamsTest.kt | 42 +
.../messages/MessageHistoryResponseTest.kt | 52 +
.../models/messages/MessageListParamsTest.kt | 82 +
.../messages/MessageListResponseTest.kt | 89 +
.../messages/MessageRetrieveParamsTest.kt | 23 +
.../messages/MessageRetrieveResponseTest.kt | 89 +
.../MessageRoutingChannelTest.kt | 79 +
.../notifications/MessageRoutingTest.kt | 36 +
.../NotificationGetContentTest.kt | 154 +
.../NotificationListParamsTest.kt | 34 +
.../NotificationListResponseTest.kt | 119 +
.../NotificationRetrieveContentParamsTest.kt | 23 +
.../notifications/checks/BaseCheckTest.kt | 44 +
.../checks/CheckDeleteParamsTest.kt | 24 +
.../checks/CheckListParamsTest.kt | 24 +
.../checks/CheckListResponseTest.kt | 60 +
.../models/notifications/checks/CheckTest.kt | 44 +
.../checks/CheckUpdateParamsTest.kt | 72 +
.../checks/CheckUpdateResponseTest.kt | 60 +
.../draft/DraftRetrieveContentParamsTest.kt | 23 +
.../profiles/ProfileCreateParamsTest.kt | 61 +
.../profiles/ProfileCreateResponseTest.kt | 34 +
.../profiles/ProfileDeleteParamsTest.kt | 23 +
.../profiles/ProfileReplaceParamsTest.kt | 61 +
.../profiles/ProfileReplaceResponseTest.kt | 34 +
.../profiles/ProfileRetrieveParamsTest.kt | 23 +
.../profiles/ProfileRetrieveResponseTest.kt | 170 +
.../profiles/ProfileUpdateParamsTest.kt | 52 +
.../profiles/lists/ListDeleteParamsTest.kt | 23 +
.../profiles/lists/ListDeleteResponseTest.kt | 34 +
.../profiles/lists/ListRetrieveParamsTest.kt | 42 +
.../lists/ListRetrieveResponseTest.kt | 213 +
.../profiles/lists/ListSubscribeParamsTest.kt | 214 +
.../lists/ListSubscribeResponseTest.kt | 34 +
.../requests/RequestArchiveParamsTest.kt | 23 +
.../api/models/send/BaseMessageSendToTest.kt | 96 +
.../api/models/send/BaseMessageTest.kt | 483 +
.../courier/api/models/send/ContentTest.kt | 107 +
.../models/send/ElementalChannelNodeTest.kt | 98 +
.../api/models/send/ElementalGroupNodeTest.kt | 78 +
.../api/models/send/ElementalNodeTest.kt | 450 +
.../api/models/send/MessageContextTest.kt | 32 +
.../courier/api/models/send/MessageTest.kt | 793 ++
.../models/send/MsTeamsBasePropertiesTest.kt | 35 +
.../courier/api/models/send/RecipientTest.kt | 633 ++
.../models/send/SendSendMessageParamsTest.kt | 641 ++
.../send/SendSendMessageResponseTest.kt | 34 +
.../models/send/SlackBasePropertiesTest.kt | 32 +
.../com/courier/api/models/send/UtmTest.kt | 47 +
.../models/tenants/DefaultPreferencesTest.kt | 63 +
.../models/tenants/TenantDeleteParamsTest.kt | 23 +
.../models/tenants/TenantListParamsTest.kt | 49 +
.../models/tenants/TenantListResponseTest.kt | 144 +
.../tenants/TenantListUsersParamsTest.kt | 44 +
.../tenants/TenantListUsersResponseTest.kt | 90 +
.../tenants/TenantRetrieveParamsTest.kt | 23 +
.../courier/api/models/tenants/TenantTest.kt | 116 +
.../models/tenants/TenantUpdateParamsTest.kt | 126 +
.../items/ItemDeleteParamsTest.kt | 24 +
.../items/ItemUpdateParamsTest.kt | 91 +
.../items/SubscriptionTopicNewTest.kt | 46 +
.../TranslationRetrieveParamsTest.kt | 24 +
.../TranslationUpdateParamsTest.kt | 35 +
.../PreferenceRetrieveParamsTest.kt | 44 +
.../PreferenceRetrieveResponseTest.kt | 72 +
.../PreferenceRetrieveTopicParamsTest.kt | 55 +
.../PreferenceRetrieveTopicResponseTest.kt | 68 +
...PreferenceUpdateOrCreateTopicParamsTest.kt | 141 +
...eferenceUpdateOrCreateTopicResponseTest.kt | 35 +
.../users/preferences/TopicPreferenceTest.kt | 56 +
.../tenants/TenantAddMultipleParamsTest.kt | 92 +
.../tenants/TenantAddSingleParamsTest.kt | 63 +
.../users/tenants/TenantAssociationTest.kt | 61 +
.../users/tenants/TenantListParamsTest.kt | 43 +
.../users/tenants/TenantListResponseTest.kt | 89 +
.../tenants/TenantRemoveAllParamsTest.kt | 23 +
.../tenants/TenantRemoveSingleParamsTest.kt | 25 +
.../tokens/TokenAddMultipleParamsTest.kt | 23 +
.../users/tokens/TokenAddSingleParamsTest.kt | 143 +
.../users/tokens/TokenDeleteParamsTest.kt | 24 +
.../users/tokens/TokenListParamsTest.kt | 23 +
.../tokens/TokenRetrieveSingleParamsTest.kt | 24 +
.../tokens/TokenRetrieveSingleResponseTest.kt | 114 +
.../users/tokens/TokenUpdateParamsTest.kt | 69 +
.../api/models/users/tokens/UserTokenTest.kt | 104 +
.../courier/api/services/ErrorHandlingTest.kt | 4013 +++++++
.../courier/api/services/ServiceParamsTest.kt | 262 +
.../async/AudienceServiceAsyncTest.kt | 117 +
.../async/AuditEventServiceAsyncTest.kt | 47 +
.../services/async/AuthServiceAsyncTest.kt | 36 +
.../async/AutomationServiceAsyncTest.kt | 100 +
.../services/async/BrandServiceAsyncTest.kt | 169 +
.../services/async/BulkServiceAsyncTest.kt | 438 +
.../services/async/InboundServiceAsyncTest.kt | 46 +
.../services/async/ListServiceAsyncTest.kt | 150 +
.../services/async/MessageServiceAsyncTest.kt | 116 +
.../async/NotificationServiceAsyncTest.kt | 49 +
.../services/async/ProfileServiceAsyncTest.kt | 127 +
.../services/async/RequestServiceAsyncTest.kt | 28 +
.../services/async/SendServiceAsyncTest.kt | 244 +
.../services/async/TenantServiceAsyncTest.kt | 143 +
.../async/TranslationServiceAsyncTest.kt | 55 +
.../lists/SubscriptionServiceAsyncTest.kt | 278 +
.../notifications/CheckServiceAsyncTest.kt | 83 +
.../notifications/DraftServiceAsyncTest.kt | 29 +
.../async/profiles/ListServiceAsyncTest.kt | 128 +
.../ItemServiceAsyncTest.kt | 63 +
.../async/users/PreferenceServiceAsyncTest.kt | 91 +
.../async/users/TenantServiceAsyncTest.kt | 129 +
.../async/users/TokenServiceAsyncTest.kt | 162 +
.../services/blocking/AudienceServiceTest.kt | 110 +
.../blocking/AuditEventServiceTest.kt | 45 +
.../api/services/blocking/AuthServiceTest.kt | 35 +
.../blocking/AutomationServiceTest.kt | 98 +
.../api/services/blocking/BrandServiceTest.kt | 162 +
.../api/services/blocking/BulkServiceTest.kt | 430 +
.../services/blocking/InboundServiceTest.kt | 45 +
.../api/services/blocking/ListServiceTest.kt | 141 +
.../services/blocking/MessageServiceTest.kt | 111 +
.../blocking/NotificationServiceTest.kt | 47 +
.../services/blocking/ProfileServiceTest.kt | 115 +
.../services/blocking/RequestServiceTest.kt | 26 +
.../api/services/blocking/SendServiceTest.kt | 243 +
.../services/blocking/TenantServiceTest.kt | 137 +
.../blocking/TranslationServiceTest.kt | 45 +
.../blocking/lists/SubscriptionServiceTest.kt | 256 +
.../notifications/CheckServiceTest.kt | 78 +
.../notifications/DraftServiceTest.kt | 28 +
.../blocking/profiles/ListServiceTest.kt | 125 +
.../defaultpreferences/ItemServiceTest.kt | 57 +
.../blocking/users/PreferenceServiceTest.kt | 88 +
.../blocking/users/TenantServiceTest.kt | 117 +
.../blocking/users/TokenServiceTest.kt | 143 +
courier-java-example/build.gradle.kts | 28 +
courier-java-lib/.keep | 4 +
courier-java-proguard-test/build.gradle.kts | 101 +
.../api/proguard/ProGuardCompatibilityTest.kt | 275 +
courier-java-proguard-test/test.pro | 9 +
courier-java/build.gradle.kts | 29 +
gradle.properties | 18 +
gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43583 bytes
gradle/wrapper/gradle-wrapper.properties | 2 +-
gradlew | 4 +-
gradlew.bat | 186 +-
sample-app/build.gradle | 19 -
sample-app/src/main/java/sample/App.java | 13 -
scripts/build | 8 +
scripts/fast-format | 46 +
scripts/format | 21 +
scripts/java-format | 7 +
scripts/kotlin-format | 7 +
scripts/lint | 23 +
scripts/mock | 41 +
scripts/test | 56 +
settings.gradle | 1 -
settings.gradle.kts | 14 +
src/main/java/com/courier/api/Courier.java | 203 -
.../java/com/courier/api/CourierBuilder.java | 44 -
.../com/courier/api/core/ClientOptions.java | 129 -
.../courier/api/core/CourierApiApiError.java | 45 -
.../com/courier/api/core/CourierApiError.java | 17 -
.../api/core/DateTimeDeserializer.java | 55 -
.../com/courier/api/core/Environment.java | 22 -
.../api/core/IdempotentRequestOptions.java | 103 -
.../java/com/courier/api/core/MediaTypes.java | 13 -
.../com/courier/api/core/ObjectMappers.java | 36 -
.../com/courier/api/core/RequestOptions.java | 71 -
.../courier/api/core/RetryInterceptor.java | 78 -
.../java/com/courier/api/core/Stream.java | 97 -
.../java/com/courier/api/core/Suppliers.java | 23 -
.../api/requests/SendMessageRequest.java | 109 -
.../resources/audiences/AudiencesClient.java | 291 -
.../requests/AudienceMembersListParams.java | 98 -
.../requests/AudienceUpdateParams.java | 150 -
.../requests/AudiencesListParams.java | 98 -
.../resources/audiences/types/Audience.java | 245 -
.../audiences/types/AudienceListResponse.java | 142 -
.../audiences/types/AudienceMember.java | 200 -
.../types/AudienceMemberGetResponse.java | 101 -
.../types/AudienceMemberListResponse.java | 143 -
.../types/AudienceUpdateResponse.java | 101 -
.../audiences/types/BaseFilterConfig.java | 109 -
.../audiences/types/ComparisonOperator.java | 46 -
.../api/resources/audiences/types/Filter.java | 94 -
.../audiences/types/FilterConfig.java | 94 -
.../audiences/types/IBaseFilterConfig.java | 8 -
.../audiences/types/LogicalOperator.java | 24 -
.../audiences/types/NestedFilterConfig.java | 149 -
.../resources/audiences/types/Operator.java | 94 -
.../audiences/types/SingleFilterConfig.java | 167 -
.../auditevents/AuditEventsClient.java | 118 -
.../requests/ListAuditEventsRequest.java | 98 -
.../resources/auditevents/types/Actor.java | 117 -
.../auditevents/types/AuditEvent.java | 238 -
.../types/GetAuditEventParams.java | 101 -
.../types/ListAuditEventsParams.java | 95 -
.../types/ListAuditEventsResponse.java | 142 -
.../resources/auditevents/types/Target.java | 117 -
.../authtokens/AuthTokensClient.java | 78 -
.../authtokens/requests/IssueTokenParams.java | 123 -
.../authtokens/types/IssueTokenResponse.java | 95 -
.../automations/AutomationsClient.java | 138 -
.../automations/types/AccessorType.java | 101 -
.../automations/types/Automation.java | 128 -
.../types/AutomationAdHocInvokeParams.java | 261 -
.../AutomationAddToBatchMaxItemsType.java | 94 -
.../types/AutomationAddToBatchRetain.java | 182 -
.../types/AutomationAddToBatchRetainType.java | 28 -
.../types/AutomationAddToBatchScope.java | 26 -
.../types/AutomationAddToBatchStep.java | 435 -
.../types/AutomationAddToDigestStep.java | 177 -
.../types/AutomationCancelStep.java | 150 -
.../types/AutomationDelayStep.java | 182 -
.../types/AutomationFetchDataStep.java | 258 -
.../types/AutomationFetchDataWebhook.java | 219 -
.../AutomationFetchDataWebhookMethod.java | 24 -
.../types/AutomationInvokeParams.java | 198 -
.../types/AutomationInvokeResponse.java | 101 -
.../types/AutomationInvokeStep.java | 167 -
.../types/AutomationInvokeTemplateParams.java | 261 -
.../types/AutomationRunContext.java | 193 -
.../types/AutomationSendListStep.java | 292 -
.../automations/types/AutomationSendStep.java | 274 -
.../automations/types/AutomationStep.java | 119 -
.../types/AutomationStepOption.java | 202 -
.../types/AutomationThrottleOnThrottle.java | 108 -
.../types/AutomationThrottleScope.java | 26 -
.../types/AutomationThrottleStep.java | 306 -
.../types/AutomationUpdateProfileStep.java | 151 -
.../types/AutomationV2SendStep.java | 168 -
.../types/IAutomationInvokeParams.java | 19 -
.../automations/types/IAutomationStep.java | 12 -
.../automations/types/MergeAlgorithm.java | 28 -
.../api/resources/brands/BrandsClient.java | 284 -
.../requests/BrandUpdateParameters.java | 172 -
.../brands/requests/ListBrandsRequest.java | 98 -
.../api/resources/brands/types/Brand.java | 336 -
.../resources/brands/types/BrandColors.java | 143 -
.../brands/types/BrandGetAllResponse.java | 142 -
.../brands/types/BrandParameters.java | 196 -
.../resources/brands/types/BrandSettings.java | 144 -
.../resources/brands/types/BrandSnippet.java | 128 -
.../resources/brands/types/BrandSnippets.java | 102 -
.../brands/types/BrandsResponse.java | 142 -
.../api/resources/bulk/BulkClient.java | 291 -
.../bulk/requests/BulkCreateJobParams.java | 102 -
.../bulk/requests/BulkGetUsersParams.java | 98 -
.../bulk/types/BulkCreateJobResponse.java | 101 -
.../bulk/types/BulkGetJobParams.java | 101 -
.../bulk/types/BulkGetJobResponse.java | 101 -
.../bulk/types/BulkGetJobUsersParams.java | 131 -
.../bulk/types/BulkGetJobUsersResponse.java | 143 -
.../resources/bulk/types/BulkIngestError.java | 123 -
.../bulk/types/BulkIngestUsersParams.java | 102 -
.../bulk/types/BulkIngestUsersResponse.java | 133 -
.../resources/bulk/types/BulkJobStatus.java | 28 -
.../bulk/types/BulkJobUserStatus.java | 26 -
.../bulk/types/BulkMessageUserResponse.java | 294 -
.../bulk/types/IInboundBulkMessageUser.java | 20 -
.../bulk/types/IInboundBulkMessageV1.java | 19 -
.../bulk/types/InboundBulkContentMessage.java | 551 -
.../bulk/types/InboundBulkMessage.java | 235 -
.../bulk/types/InboundBulkMessageUser.java | 200 -
.../bulk/types/InboundBulkMessageV1.java | 211 -
.../bulk/types/InboundBulkMessageV2.java | 94 -
.../types/InboundBulkTemplateMessage.java | 550 -
.../api/resources/bulk/types/JobDetails.java | 200 -
.../errors/CourierApiAlreadyExistsError.java | 27 -
.../errors/CourierApiBadRequestError.java | 27 -
.../errors/CourierApiConflictError.java | 27 -
.../CourierApiMessageNotFoundError.java | 27 -
.../errors/CourierApiNotFoundError.java | 27 -
.../CourierApiPaymentRequiredError.java | 27 -
.../commons/types/AlreadyExists.java | 114 -
.../resources/commons/types/BadRequest.java | 114 -
.../resources/commons/types/BaseError.java | 109 -
.../types/BaseTemplateTenantAssociation.java | 241 -
.../commons/types/ChannelClassification.java | 32 -
.../commons/types/ChannelPreference.java | 101 -
.../api/resources/commons/types/Conflict.java | 114 -
.../api/resources/commons/types/Email.java | 123 -
.../resources/commons/types/IBaseError.java | 8 -
.../types/IBaseTemplateTenantAssociation.java | 16 -
.../ISingleTemplateTenantAssociation.java | 8 -
.../types/ListTemplateTenantAssociation.java | 265 -
.../commons/types/MessageNotFound.java | 114 -
.../api/resources/commons/types/NotFound.java | 114 -
.../types/NotificationPreferenceDetails.java | 166 -
.../api/resources/commons/types/Paging.java | 131 -
.../commons/types/PaymentRequired.java | 114 -
.../commons/types/PreferenceStatus.java | 26 -
.../commons/types/RecipientPreferences.java | 120 -
.../api/resources/commons/types/Rule.java | 131 -
.../SingleTemplateTenantAssociation.java | 267 -
.../commons/types/TenantTemplateData.java | 126 -
.../types/TenantTemplateDataNoContent.java | 102 -
.../commons/types/UserTenantAssociation.java | 216 -
.../api/resources/inbound/InboundClient.java | 88 -
.../inbound/types/InboundTrackEvent.java | 225 -
.../inbound/types/TrackAcceptedResponse.java | 108 -
.../api/resources/lists/ListsClient.java | 578 -
.../lists/requests/AddSubscribersToList.java | 103 -
.../lists/requests/GetAllListsRequest.java | 124 -
.../GetSubscriptionForListRequest.java | 98 -
.../lists/requests/RestoreListRequest.java | 59 -
.../requests/SubscribeUserToListRequest.java | 97 -
.../requests/SubscribeUsersToListRequest.java | 104 -
.../api/resources/lists/types/List.java | 189 -
.../lists/types/ListGetAllResponse.java | 141 -
.../types/ListGetSubscriptionsResponse.java | 143 -
.../resources/lists/types/ListPutParams.java | 133 -
.../types/ListSubscriptionRecipient.java | 166 -
.../types/PutSubscriptionsRecipient.java | 133 -
.../resources/messages/MessagesClient.java | 370 -
.../requests/GetMessageHistoryRequest.java | 98 -
.../requests/ListMessagesRequest.java | 480 -
.../messages/types/IMessageDetails.java | 32 -
.../messages/types/ListMessagesResponse.java | 161 -
.../messages/types/MessageDetails.java | 513 -
.../types/MessageDetailsExtended.java | 546 -
.../types/MessageHistoryResponse.java | 102 -
.../messages/types/MessageStatus.java | 50 -
.../api/resources/messages/types/Reason.java | 38 -
.../messages/types/RenderOutput.java | 170 -
.../messages/types/RenderOutputResponse.java | 105 -
.../messages/types/RenderedMessageBlock.java | 137 -
.../types/RenderedMessageContent.java | 288 -
.../notifications/NotificationsClient.java | 270 -
.../requests/NotificationListParams.java | 121 -
.../SubmissionChecksReplaceParams.java | 103 -
.../notifications/types/BaseCheck.java | 131 -
.../notifications/types/BlockType.java | 38 -
.../resources/notifications/types/Check.java | 153 -
.../notifications/types/CheckStatus.java | 26 -
.../notifications/types/IBaseCheck.java | 12 -
.../notifications/types/MessageRouting.java | 144 -
.../types/MessageRoutingChannel.java | 94 -
.../types/MessageRoutingMethod.java | 24 -
.../notifications/types/Notification.java | 288 -
.../types/NotificationBlock.java | 279 -
.../types/NotificationChannel.java | 225 -
.../types/NotificationChannelContent.java | 118 -
.../types/NotificationContent.java | 94 -
.../types/NotificationContentHierarchy.java | 118 -
.../types/NotificationGetContentResponse.java | 144 -
.../types/NotificationListResponse.java | 143 -
.../notifications/types/NotificationTag.java | 102 -
.../types/NotificationTagData.java | 123 -
.../types/SubmissionChecksGetResponse.java | 102 -
.../SubmissionChecksReplaceResponse.java | 102 -
.../resources/profiles/ProfilesClient.java | 469 -
.../requests/GetListSubscriptionsRequest.java | 98 -
.../requests/MergeProfileRequest.java | 101 -
.../requests/ReplaceProfileRequest.java | 101 -
.../api/resources/profiles/types/Address.java | 231 -
.../profiles/types/AirshipProfile.java | 142 -
.../types/AirshipProfileAudience.java | 101 -
.../types/DeleteListSubscriptionResponse.java | 65 -
.../api/resources/profiles/types/Discord.java | 94 -
.../api/resources/profiles/types/Expo.java | 94 -
.../types/GetListSubscriptionsList.java | 229 -
.../types/GetListSubscriptionsResponse.java | 154 -
.../types/IMsTeamsBaseProperties.java | 10 -
.../profiles/types/ISlackBaseProperties.java | 8 -
.../resources/profiles/types/Intercom.java | 123 -
.../profiles/types/IntercomRecipient.java | 101 -
.../profiles/types/MergeProfileResponse.java | 65 -
.../api/resources/profiles/types/MsTeams.java | 130 -
.../profiles/types/MsTeamsBaseProperties.java | 125 -
.../profiles/types/MultipleTokens.java | 102 -
.../resources/profiles/types/Pagerduty.java | 169 -
.../profiles/types/ProfileGetParameters.java | 101 -
.../profiles/types/ProfileGetResponse.java | 128 -
.../profiles/types/ProfileUpdateRequest.java | 105 -
.../types/ReplaceProfileResponse.java | 65 -
.../profiles/types/SendDirectMessage.java | 101 -
.../profiles/types/SendToChannel.java | 101 -
.../types/SendToMsTeamsChannelId.java | 150 -
.../types/SendToMsTeamsChannelName.java | 178 -
.../types/SendToMsTeamsConversationId.java | 150 -
.../profiles/types/SendToMsTeamsEmail.java | 148 -
.../profiles/types/SendToMsTeamsUserId.java | 148 -
.../profiles/types/SendToSlackChannel.java | 124 -
.../profiles/types/SendToSlackEmail.java | 124 -
.../profiles/types/SendToSlackUserId.java | 124 -
.../api/resources/profiles/types/Slack.java | 106 -
.../profiles/types/SlackBaseProperties.java | 102 -
.../resources/profiles/types/SnoozeRule.java | 145 -
.../profiles/types/SnoozeRuleType.java | 22 -
.../types/SubscribeToListsRequest.java | 103 -
.../SubscribeToListsRequestListObject.java | 133 -
.../types/SubscribeToListsResponse.java | 65 -
.../api/resources/profiles/types/Token.java | 101 -
.../resources/profiles/types/UserProfile.java | 925 --
.../types/UserProfileFirebaseToken.java | 96 -
.../profiles/types/UserProfilePatch.java | 166 -
.../profiles/types/WebhookAuthMode.java | 26 -
.../profiles/types/WebhookAuthentication.java | 223 -
.../profiles/types/WebhookMethod.java | 24 -
.../profiles/types/WebhookProfile.java | 260 -
.../profiles/types/WebhookProfileType.java | 24 -
.../resources/send/types/AudienceFilter.java | 114 -
.../send/types/AudienceRecipient.java | 171 -
.../api/resources/send/types/BaseMessage.java | 397 -
.../send/types/BaseMessageSendTo.java | 99 -
.../send/types/BaseSocialPresence.java | 101 -
.../send/types/BrandSettingsEmail.java | 169 -
.../send/types/BrandSettingsInApp.java | 316 -
.../types/BrandSettingsSocialPresence.java | 219 -
.../resources/send/types/BrandTemplate.java | 300 -
.../send/types/BrandTemplateOverride.java | 397 -
.../api/resources/send/types/Channel.java | 272 -
.../resources/send/types/ChannelMetadata.java | 95 -
.../resources/send/types/ChannelSource.java | 26 -
.../api/resources/send/types/Content.java | 94 -
.../resources/send/types/ContentMessage.java | 580 -
.../api/resources/send/types/Criteria.java | 28 -
.../api/resources/send/types/Delay.java | 123 -
.../send/types/ElementalActionNode.java | 476 -
.../send/types/ElementalBaseNode.java | 174 -
.../send/types/ElementalChannelNode.java | 317 -
.../send/types/ElementalContent.java | 181 -
.../send/types/ElementalContentSugar.java | 137 -
.../send/types/ElementalDividerNode.java | 201 -
.../send/types/ElementalGroupNode.java | 208 -
.../send/types/ElementalImageNode.java | 395 -
.../send/types/ElementalMetaNode.java | 201 -
.../resources/send/types/ElementalNode.java | 539 -
.../send/types/ElementalQuoteNode.java | 382 -
.../send/types/ElementalTextNode.java | 588 -
.../api/resources/send/types/EmailFooter.java | 118 -
.../api/resources/send/types/EmailHead.java | 131 -
.../api/resources/send/types/EmailHeader.java | 165 -
.../resources/send/types/ExpiresInType.java | 93 -
.../api/resources/send/types/Expiry.java | 145 -
.../send/types/IActionButtonStyle.java | 24 -
.../api/resources/send/types/IAlignment.java | 28 -
.../resources/send/types/IBaseMessage.java | 31 -
.../send/types/IBaseMessageSendTo.java | 10 -
.../resources/send/types/IBrandTemplate.java | 22 -
.../send/types/IElementalBaseNode.java | 17 -
.../send/types/IListPatternRecipientType.java | 6 -
.../send/types/IListRecipientType.java | 6 -
.../send/types/IProfilePreferences.java | 152 -
.../send/types/IUserRecipientType.java | 6 -
.../api/resources/send/types/Icons.java | 117 -
.../resources/send/types/InAppPlacement.java | 28 -
.../types/InvalidListPatternRecipient.java | 123 -
.../send/types/InvalidListRecipient.java | 123 -
.../send/types/InvalidUserRecipient.java | 123 -
.../api/resources/send/types/ListFilter.java | 114 -
.../send/types/ListPatternRecipient.java | 120 -
.../send/types/ListPatternRecipientType.java | 59 -
.../resources/send/types/ListRecipient.java | 144 -
.../send/types/ListRecipientType.java | 59 -
.../api/resources/send/types/Locale.java | 101 -
.../api/resources/send/types/Logo.java | 117 -
.../api/resources/send/types/Message.java | 94 -
.../resources/send/types/MessageContext.java | 99 -
.../resources/send/types/MessageMetadata.java | 182 -
.../send/types/MessagePreferences.java | 108 -
.../send/types/MessageProvidersType.java | 178 -
.../send/types/MessageRecipient.java | 96 -
.../api/resources/send/types/Metadata.java | 95 -
.../send/types/MsTeamsRecipient.java | 102 -
.../send/types/PagerdutyRecipient.java | 102 -
.../api/resources/send/types/Preference.java | 199 -
.../api/resources/send/types/Preferences.java | 102 -
.../api/resources/send/types/Recipient.java | 180 -
.../api/resources/send/types/Routing.java | 160 -
.../resources/send/types/RoutingMethod.java | 24 -
.../api/resources/send/types/RuleType.java | 26 -
.../resources/send/types/SlackRecipient.java | 102 -
.../resources/send/types/TemplateMessage.java | 580 -
.../api/resources/send/types/TextAlign.java | 26 -
.../api/resources/send/types/TextStyle.java | 28 -
.../api/resources/send/types/Timeout.java | 193 -
.../api/resources/send/types/Timeouts.java | 117 -
.../send/types/TrackingOverride.java | 101 -
.../resources/send/types/UserRecipient.java | 321 -
.../send/types/UserRecipientType.java | 59 -
.../courier/api/resources/send/types/Utm.java | 193 -
.../send/types/WebhookRecipient.java | 102 -
.../send/types/WidgetBackground.java | 118 -
.../resources/templates/TemplatesClient.java | 76 -
.../requests/ListTemplatesRequest.java | 98 -
.../types/ListTemplatesResponse.java | 154 -
.../types/NotificationTemplates.java | 288 -
.../templates/types/RoutingStrategy.java | 160 -
.../types/RoutingStrategyMethod.java | 24 -
.../api/resources/templates/types/Tag.java | 102 -
.../resources/templates/types/TagData.java | 137 -
.../api/resources/tenants/TenantsClient.java | 452 -
.../GetTemplateListByTenantParams.java | 124 -
.../tenants/requests/ListTenantParams.java | 153 -
.../requests/ListUsersForTenantParams.java | 125 -
.../requests/TenantCreateOrReplaceParams.java | 305 -
.../tenants/types/DefaultPreferences.java | 96 -
.../types/GetTemplateByTenantResponse.java | 268 -
.../tenants/types/ISubscriptionTopicNew.java | 16 -
.../types/ListTemplatesByTenantResponse.java | 261 -
.../types/ListUsersForTenantResponse.java | 261 -
.../tenants/types/SubscriptionTopic.java | 215 -
.../tenants/types/SubscriptionTopicNew.java | 184 -
.../types/SubscriptionTopicStatus.java | 26 -
.../api/resources/tenants/types/Tenant.java | 343 -
.../tenants/types/TenantListResponse.java | 279 -
.../translations/TranslationsClient.java | 137 -
.../api/resources/users/UsersClient.java | 40 -
.../users/preferences/PreferencesClient.java | 224 -
.../requests/UserPreferencesParams.java | 98 -
.../requests/UserPreferencesTopicParams.java | 98 -
.../requests/UserPreferencesUpdateParams.java | 140 -
.../preferences/types/TopicPreference.java | 255 -
.../types/TopicPreferenceUpdate.java | 175 -
.../types/UserPreferencesGetResponse.java | 101 -
.../types/UserPreferencesListResponse.java | 161 -
.../types/UserPreferencesUpdateResponse.java | 101 -
.../users/tenants/TenantsClient.java | 294 -
.../AddUserToMultipleTenantsParams.java | 104 -
.../AddUserToSingleTenantsParams.java | 96 -
.../requests/ListTenantsForUserParams.java | 125 -
.../AddUserToSingleTenantsParamsProfile.java | 250 -
.../types/ListTenantsForUserResponse.java | 261 -
.../resources/users/tokens/TokensClient.java | 338 -
.../tokens/types/DeleteUserTokenOpts.java | 123 -
.../resources/users/tokens/types/Device.java | 235 -
.../users/tokens/types/ExpiryDate.java | 93 -
.../users/tokens/types/GetUserTokenOpts.java | 123 -
.../tokens/types/GetUserTokenResponse.java | 380 -
.../users/tokens/types/GetUserTokensOpts.java | 101 -
.../users/tokens/types/IUserToken.java | 20 -
.../resources/users/tokens/types/PatchOp.java | 32 -
.../users/tokens/types/PatchOperation.java | 174 -
.../tokens/types/PatchUserTokenOpts.java | 102 -
.../users/tokens/types/ProviderKey.java | 28 -
.../users/tokens/types/PutUserTokenOpts.java | 123 -
.../users/tokens/types/PutUserTokensOpts.java | 141 -
.../users/tokens/types/TokenStatus.java | 28 -
.../users/tokens/types/Tracking.java | 181 -
.../users/tokens/types/UserToken.java | 296 -
.../api/types/SendMessageResponse.java | 112 -
src/test/java/com/courier/api/TestClient.java | 11 -
952 files changed, 146247 insertions(+), 57067 deletions(-)
create mode 100644 .devcontainer/Dockerfile
create mode 100644 .devcontainer/devcontainer.json
delete mode 100644 .fernignore
create mode 100644 .gitattributes
delete mode 100755 .publish/prepare.sh
create mode 100644 .stats.yml
create mode 100644 SECURITY.md
delete mode 100644 build.gradle
create mode 100644 build.gradle.kts
create mode 100644 buildSrc/build.gradle.kts
create mode 100644 buildSrc/src/main/kotlin/courier.java.gradle.kts
create mode 100644 buildSrc/src/main/kotlin/courier.kotlin.gradle.kts
create mode 100644 buildSrc/src/main/kotlin/courier.publish.gradle.kts
create mode 100644 courier-java-client-okhttp/build.gradle.kts
create mode 100644 courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClient.kt
create mode 100644 courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClientAsync.kt
create mode 100644 courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/OkHttpClient.kt
create mode 100644 courier-java-core/build.gradle.kts
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/client/CourierClient.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/BaseDeserializer.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/BaseSerializer.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/Check.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/ClientOptions.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/DefaultSleeper.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/ObjectMappers.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/Params.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachable.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachableExecutorService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachableSleeper.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/PrepareRequest.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/Properties.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/RequestOptions.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/Sleeper.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/Timeout.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/Utils.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/Values.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/handlers/EmptyHandler.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/handlers/ErrorHandler.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/handlers/JsonHandler.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/handlers/StringHandler.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/AsyncStreamResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/Headers.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/HttpClient.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/HttpMethod.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/HttpRequest.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/HttpRequestBodies.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/HttpRequestBody.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/HttpResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/HttpResponseFor.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/PhantomReachableClosingHttpClient.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/PhantomReachableClosingStreamResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/QueryParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/RetryingHttpClient.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/core/http/StreamResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/BadRequestException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/CourierException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/CourierInvalidDataException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/CourierIoException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/CourierRetryableException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/CourierServiceException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/InternalServerException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/NotFoundException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/PermissionDeniedException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/RateLimitException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/UnauthorizedException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/UnexpectedStatusCodeException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/errors/UnprocessableEntityException.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/Audience.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/AudienceDeleteParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/AudienceListMembersParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/AudienceListMembersResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/AudienceListParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/AudienceListResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/AudienceRetrieveParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/AudienceUpdateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/AudienceUpdateResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/Filter.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/FilterConfig.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/NestedFilterConfig.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/audiences/Paging.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/auditevents/AuditEvent.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/auditevents/AuditEventListParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/auditevents/AuditEventListResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/auditevents/AuditEventRetrieveParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/auth/AuthIssueTokenParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/auth/AuthIssueTokenResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/automations/AutomationInvokeAdHocParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/automations/AutomationInvokeByTemplateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/automations/invoke/AutomationInvokeParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/automations/invoke/AutomationInvokeResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/automations/invoke/AutomationStep.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/automations/invoke/MergeAlgorithm.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/brands/Brand.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/brands/BrandCreateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/brands/BrandDeleteParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/brands/BrandListParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/brands/BrandListResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/brands/BrandRetrieveParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/brands/BrandSettings.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/brands/BrandSnippets.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/brands/BrandUpdateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/bulk/BulkAddUsersParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/bulk/BulkCreateJobParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/bulk/BulkCreateJobResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/bulk/BulkListUsersParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/bulk/BulkListUsersResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/bulk/BulkRetrieveJobParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/bulk/BulkRetrieveJobResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/bulk/BulkRunJobParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/bulk/InboundBulkMessage.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/bulk/InboundBulkMessageUser.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/bulk/UserRecipient.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/inbound/InboundTrackEventParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/inbound/InboundTrackEventResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/List.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/ListDeleteParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/ListListParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/ListListResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/ListRestoreParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/ListRetrieveParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/ListUpdateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/subscriptions/PutSubscriptionsRecipient.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/subscriptions/RecipientPreferences.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionAddParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionListParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionListResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionSubscribeParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionSubscribeUserParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionUnsubscribeUserParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/messages/MessageCancelParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/messages/MessageDetails.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/messages/MessageGetContentParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/messages/MessageGetContentResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/messages/MessageHistoryParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/messages/MessageHistoryResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/messages/MessageListParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/messages/MessageListResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/messages/MessageRetrieveParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/messages/MessageRetrieveResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/MessageRouting.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/MessageRoutingChannel.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/NotificationGetContent.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/NotificationListParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/NotificationListResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/NotificationRetrieveContentParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/checks/BaseCheck.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/checks/Check.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/checks/CheckDeleteParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/checks/CheckListParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/checks/CheckListResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/checks/CheckUpdateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/checks/CheckUpdateResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/notifications/draft/DraftRetrieveContentParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/ProfileCreateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/ProfileCreateResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/ProfileDeleteParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/ProfileReplaceParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/ProfileReplaceResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/ProfileRetrieveParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/ProfileRetrieveResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/ProfileUpdateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/lists/ListDeleteParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/lists/ListDeleteResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/lists/ListRetrieveParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/lists/ListRetrieveResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/lists/ListSubscribeParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/profiles/lists/ListSubscribeResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/requests/RequestArchiveParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/BaseMessage.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/BaseMessageSendTo.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/Content.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/ElementalChannelNode.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/ElementalGroupNode.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/ElementalNode.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/Message.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/MessageContext.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/MsTeamsBaseProperties.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/Recipient.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/RoutingMethod.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/SendSendMessageParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/SendSendMessageResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/SlackBaseProperties.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/send/Utm.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/DefaultPreferences.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/Tenant.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/TenantDeleteParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/TenantListParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/TenantListResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/TenantListUsersParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/TenantListUsersResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/TenantRetrieveParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/TenantUpdateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/defaultpreferences/items/ChannelClassification.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/defaultpreferences/items/ItemDeleteParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/defaultpreferences/items/ItemUpdateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/tenants/defaultpreferences/items/SubscriptionTopicNew.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/translations/TranslationRetrieveParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/translations/TranslationUpdateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/preferences/PreferenceRetrieveParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/preferences/PreferenceRetrieveResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/preferences/PreferenceRetrieveTopicParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/preferences/PreferenceRetrieveTopicResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/preferences/PreferenceStatus.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/preferences/PreferenceUpdateOrCreateTopicParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/preferences/PreferenceUpdateOrCreateTopicResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/preferences/TopicPreference.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tenants/TenantAddMultipleParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tenants/TenantAddSingleParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tenants/TenantAssociation.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tenants/TenantListParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tenants/TenantListResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tenants/TenantRemoveAllParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tenants/TenantRemoveSingleParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tokens/TokenAddMultipleParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tokens/TokenAddSingleParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tokens/TokenDeleteParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tokens/TokenListParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tokens/TokenRetrieveSingleParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tokens/TokenRetrieveSingleResponse.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tokens/TokenUpdateParams.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/models/users/tokens/UserToken.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/AudienceServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/AudienceServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/AuditEventServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/AuditEventServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/AuthServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/AuthServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/AutomationServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/AutomationServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/BrandServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/BrandServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/BulkServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/BulkServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/InboundServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/InboundServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/ListServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/ListServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/MessageServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/MessageServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/NotificationServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/NotificationServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/ProfileServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/ProfileServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/RequestServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/RequestServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/SendServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/SendServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/TenantServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/TenantServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/TranslationServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/TranslationServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/UserServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/UserServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/automations/InvokeServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/automations/InvokeServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/lists/SubscriptionServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/lists/SubscriptionServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/notifications/CheckServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/notifications/CheckServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/notifications/DraftServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/notifications/DraftServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/profiles/ListServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/profiles/ListServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/tenants/DefaultPreferenceServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/tenants/DefaultPreferenceServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/tenants/defaultpreferences/ItemServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/tenants/defaultpreferences/ItemServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/users/PreferenceServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/users/PreferenceServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/users/TenantServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/users/TenantServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/users/TokenServiceAsync.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/async/users/TokenServiceAsyncImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/AudienceService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/AudienceServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/AuditEventService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/AuditEventServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/AuthService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/AuthServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/AutomationService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/AutomationServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/BrandService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/BrandServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/BulkService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/BulkServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/InboundService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/InboundServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/ListService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/ListServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/MessageService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/MessageServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/NotificationService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/NotificationServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/ProfileService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/ProfileServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/RequestService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/RequestServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/SendService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/SendServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/TenantService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/TenantServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/TranslationService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/TranslationServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/UserService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/UserServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/automations/InvokeService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/automations/InvokeServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/lists/SubscriptionService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/lists/SubscriptionServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/notifications/CheckService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/notifications/CheckServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/notifications/DraftService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/notifications/DraftServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/profiles/ListService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/profiles/ListServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/tenants/DefaultPreferenceService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/tenants/DefaultPreferenceServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/tenants/defaultpreferences/ItemService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/tenants/defaultpreferences/ItemServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/users/PreferenceService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/users/PreferenceServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/users/TenantService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/users/TenantServiceImpl.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/users/TokenService.kt
create mode 100644 courier-java-core/src/main/kotlin/com/courier/api/services/blocking/users/TokenServiceImpl.kt
create mode 100644 courier-java-core/src/main/resources/META-INF/proguard/courier-java-core.pro
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/TestServerExtension.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/core/ClientOptionsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/core/ObjectMappersTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/core/PhantomReachableTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/core/UtilsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/core/ValuesTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/core/http/AsyncStreamResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/core/http/HeadersTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/core/http/QueryParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/core/http/RetryingHttpClientTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/AudienceDeleteParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/AudienceListMembersParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/AudienceListMembersResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/AudienceListParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/AudienceListResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/AudienceRetrieveParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/AudienceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/AudienceUpdateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/AudienceUpdateResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/FilterConfigTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/FilterTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/NestedFilterConfigTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/audiences/PagingTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/auditevents/AuditEventListParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/auditevents/AuditEventListResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/auditevents/AuditEventRetrieveParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/auditevents/AuditEventTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/auth/AuthIssueTokenParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/auth/AuthIssueTokenResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/automations/AutomationInvokeAdHocParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/automations/AutomationInvokeByTemplateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/automations/invoke/AutomationInvokeParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/automations/invoke/AutomationInvokeResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/automations/invoke/AutomationStepTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/brands/BrandCreateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/brands/BrandDeleteParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/brands/BrandListParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/brands/BrandListResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/brands/BrandRetrieveParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/brands/BrandSettingsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/brands/BrandSnippetsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/brands/BrandTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/brands/BrandUpdateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/bulk/BulkAddUsersParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/bulk/BulkCreateJobParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/bulk/BulkCreateJobResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/bulk/BulkListUsersParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/bulk/BulkListUsersResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/bulk/BulkRetrieveJobParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/bulk/BulkRetrieveJobResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/bulk/BulkRunJobParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/bulk/InboundBulkMessageTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/bulk/InboundBulkMessageUserTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/bulk/UserRecipientTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/inbound/InboundTrackEventParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/inbound/InboundTrackEventResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/ListDeleteParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/ListListParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/ListListResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/ListRestoreParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/ListRetrieveParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/ListTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/ListUpdateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/subscriptions/PutSubscriptionsRecipientTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/subscriptions/RecipientPreferencesTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionAddParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionListParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionListResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionSubscribeParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionSubscribeUserParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/lists/subscriptions/SubscriptionUnsubscribeUserParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/messages/MessageCancelParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/messages/MessageDetailsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/messages/MessageGetContentParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/messages/MessageGetContentResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/messages/MessageHistoryParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/messages/MessageHistoryResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/messages/MessageListParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/messages/MessageListResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/messages/MessageRetrieveParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/messages/MessageRetrieveResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/MessageRoutingChannelTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/MessageRoutingTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/NotificationGetContentTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/NotificationListParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/NotificationListResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/NotificationRetrieveContentParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/checks/BaseCheckTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/checks/CheckDeleteParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/checks/CheckListParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/checks/CheckListResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/checks/CheckTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/checks/CheckUpdateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/checks/CheckUpdateResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/notifications/draft/DraftRetrieveContentParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/ProfileCreateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/ProfileCreateResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/ProfileDeleteParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/ProfileReplaceParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/ProfileReplaceResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/ProfileRetrieveParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/ProfileRetrieveResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/ProfileUpdateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/lists/ListDeleteParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/lists/ListDeleteResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/lists/ListRetrieveParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/lists/ListRetrieveResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/lists/ListSubscribeParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/profiles/lists/ListSubscribeResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/requests/RequestArchiveParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/BaseMessageSendToTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/BaseMessageTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/ContentTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/ElementalChannelNodeTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/ElementalGroupNodeTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/ElementalNodeTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/MessageContextTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/MessageTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/MsTeamsBasePropertiesTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/RecipientTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/SendSendMessageParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/SendSendMessageResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/SlackBasePropertiesTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/send/UtmTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/DefaultPreferencesTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/TenantDeleteParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/TenantListParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/TenantListResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/TenantListUsersParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/TenantListUsersResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/TenantRetrieveParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/TenantTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/TenantUpdateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/defaultpreferences/items/ItemDeleteParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/defaultpreferences/items/ItemUpdateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/tenants/defaultpreferences/items/SubscriptionTopicNewTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/translations/TranslationRetrieveParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/translations/TranslationUpdateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/preferences/PreferenceRetrieveParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/preferences/PreferenceRetrieveResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/preferences/PreferenceRetrieveTopicParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/preferences/PreferenceRetrieveTopicResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/preferences/PreferenceUpdateOrCreateTopicParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/preferences/PreferenceUpdateOrCreateTopicResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/preferences/TopicPreferenceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tenants/TenantAddMultipleParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tenants/TenantAddSingleParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tenants/TenantAssociationTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tenants/TenantListParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tenants/TenantListResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tenants/TenantRemoveAllParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tenants/TenantRemoveSingleParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tokens/TokenAddMultipleParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tokens/TokenAddSingleParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tokens/TokenDeleteParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tokens/TokenListParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tokens/TokenRetrieveSingleParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tokens/TokenRetrieveSingleResponseTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tokens/TokenUpdateParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/models/users/tokens/UserTokenTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/ErrorHandlingTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/ServiceParamsTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/AudienceServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/AuditEventServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/AuthServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/AutomationServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/BrandServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/BulkServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/InboundServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/ListServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/MessageServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/NotificationServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/ProfileServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/RequestServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/SendServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/TenantServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/TranslationServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/lists/SubscriptionServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/notifications/CheckServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/notifications/DraftServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/profiles/ListServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/tenants/defaultpreferences/ItemServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/users/PreferenceServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/users/TenantServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/async/users/TokenServiceAsyncTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/AudienceServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/AuditEventServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/AuthServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/AutomationServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/BrandServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/BulkServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/InboundServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/ListServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/MessageServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/NotificationServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/ProfileServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/RequestServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/SendServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/TenantServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/TranslationServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/lists/SubscriptionServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/notifications/CheckServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/notifications/DraftServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/profiles/ListServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/tenants/defaultpreferences/ItemServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/users/PreferenceServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/users/TenantServiceTest.kt
create mode 100644 courier-java-core/src/test/kotlin/com/courier/api/services/blocking/users/TokenServiceTest.kt
create mode 100644 courier-java-example/build.gradle.kts
create mode 100644 courier-java-lib/.keep
create mode 100644 courier-java-proguard-test/build.gradle.kts
create mode 100644 courier-java-proguard-test/src/test/kotlin/com/courier/api/proguard/ProGuardCompatibilityTest.kt
create mode 100644 courier-java-proguard-test/test.pro
create mode 100644 courier-java/build.gradle.kts
delete mode 100644 sample-app/build.gradle
delete mode 100644 sample-app/src/main/java/sample/App.java
create mode 100755 scripts/build
create mode 100755 scripts/fast-format
create mode 100755 scripts/format
create mode 100755 scripts/java-format
create mode 100755 scripts/kotlin-format
create mode 100755 scripts/lint
create mode 100755 scripts/mock
create mode 100755 scripts/test
delete mode 100644 settings.gradle
create mode 100644 settings.gradle.kts
delete mode 100644 src/main/java/com/courier/api/Courier.java
delete mode 100644 src/main/java/com/courier/api/CourierBuilder.java
delete mode 100644 src/main/java/com/courier/api/core/ClientOptions.java
delete mode 100644 src/main/java/com/courier/api/core/CourierApiApiError.java
delete mode 100644 src/main/java/com/courier/api/core/CourierApiError.java
delete mode 100644 src/main/java/com/courier/api/core/DateTimeDeserializer.java
delete mode 100644 src/main/java/com/courier/api/core/Environment.java
delete mode 100644 src/main/java/com/courier/api/core/IdempotentRequestOptions.java
delete mode 100644 src/main/java/com/courier/api/core/MediaTypes.java
delete mode 100644 src/main/java/com/courier/api/core/ObjectMappers.java
delete mode 100644 src/main/java/com/courier/api/core/RequestOptions.java
delete mode 100644 src/main/java/com/courier/api/core/RetryInterceptor.java
delete mode 100644 src/main/java/com/courier/api/core/Stream.java
delete mode 100644 src/main/java/com/courier/api/core/Suppliers.java
delete mode 100644 src/main/java/com/courier/api/requests/SendMessageRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/AudiencesClient.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/requests/AudienceMembersListParams.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/requests/AudienceUpdateParams.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/requests/AudiencesListParams.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/Audience.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/AudienceListResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/AudienceMember.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/AudienceMemberGetResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/AudienceMemberListResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/AudienceUpdateResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/BaseFilterConfig.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/ComparisonOperator.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/Filter.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/FilterConfig.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/IBaseFilterConfig.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/LogicalOperator.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/NestedFilterConfig.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/Operator.java
delete mode 100644 src/main/java/com/courier/api/resources/audiences/types/SingleFilterConfig.java
delete mode 100644 src/main/java/com/courier/api/resources/auditevents/AuditEventsClient.java
delete mode 100644 src/main/java/com/courier/api/resources/auditevents/requests/ListAuditEventsRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/auditevents/types/Actor.java
delete mode 100644 src/main/java/com/courier/api/resources/auditevents/types/AuditEvent.java
delete mode 100644 src/main/java/com/courier/api/resources/auditevents/types/GetAuditEventParams.java
delete mode 100644 src/main/java/com/courier/api/resources/auditevents/types/ListAuditEventsParams.java
delete mode 100644 src/main/java/com/courier/api/resources/auditevents/types/ListAuditEventsResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/auditevents/types/Target.java
delete mode 100644 src/main/java/com/courier/api/resources/authtokens/AuthTokensClient.java
delete mode 100644 src/main/java/com/courier/api/resources/authtokens/requests/IssueTokenParams.java
delete mode 100644 src/main/java/com/courier/api/resources/authtokens/types/IssueTokenResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/AutomationsClient.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AccessorType.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/Automation.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationAdHocInvokeParams.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationAddToBatchMaxItemsType.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationAddToBatchRetain.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationAddToBatchRetainType.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationAddToBatchScope.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationAddToBatchStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationAddToDigestStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationCancelStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationDelayStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationFetchDataStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationFetchDataWebhook.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationFetchDataWebhookMethod.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationInvokeParams.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationInvokeResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationInvokeStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationInvokeTemplateParams.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationRunContext.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationSendListStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationSendStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationStepOption.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationThrottleOnThrottle.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationThrottleScope.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationThrottleStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationUpdateProfileStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/AutomationV2SendStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/IAutomationInvokeParams.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/IAutomationStep.java
delete mode 100644 src/main/java/com/courier/api/resources/automations/types/MergeAlgorithm.java
delete mode 100644 src/main/java/com/courier/api/resources/brands/BrandsClient.java
delete mode 100644 src/main/java/com/courier/api/resources/brands/requests/BrandUpdateParameters.java
delete mode 100644 src/main/java/com/courier/api/resources/brands/requests/ListBrandsRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/brands/types/Brand.java
delete mode 100644 src/main/java/com/courier/api/resources/brands/types/BrandColors.java
delete mode 100644 src/main/java/com/courier/api/resources/brands/types/BrandGetAllResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/brands/types/BrandParameters.java
delete mode 100644 src/main/java/com/courier/api/resources/brands/types/BrandSettings.java
delete mode 100644 src/main/java/com/courier/api/resources/brands/types/BrandSnippet.java
delete mode 100644 src/main/java/com/courier/api/resources/brands/types/BrandSnippets.java
delete mode 100644 src/main/java/com/courier/api/resources/brands/types/BrandsResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/BulkClient.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/requests/BulkCreateJobParams.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/requests/BulkGetUsersParams.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/BulkCreateJobResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/BulkGetJobParams.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/BulkGetJobResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/BulkGetJobUsersParams.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/BulkGetJobUsersResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/BulkIngestError.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/BulkIngestUsersParams.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/BulkIngestUsersResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/BulkJobStatus.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/BulkJobUserStatus.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/BulkMessageUserResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/IInboundBulkMessageUser.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/IInboundBulkMessageV1.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/InboundBulkContentMessage.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/InboundBulkMessage.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/InboundBulkMessageUser.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/InboundBulkMessageV1.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/InboundBulkMessageV2.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/InboundBulkTemplateMessage.java
delete mode 100644 src/main/java/com/courier/api/resources/bulk/types/JobDetails.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/errors/CourierApiAlreadyExistsError.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/errors/CourierApiBadRequestError.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/errors/CourierApiConflictError.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/errors/CourierApiMessageNotFoundError.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/errors/CourierApiNotFoundError.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/errors/CourierApiPaymentRequiredError.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/AlreadyExists.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/BadRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/BaseError.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/BaseTemplateTenantAssociation.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/ChannelClassification.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/ChannelPreference.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/Conflict.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/Email.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/IBaseError.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/IBaseTemplateTenantAssociation.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/ISingleTemplateTenantAssociation.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/ListTemplateTenantAssociation.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/MessageNotFound.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/NotFound.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/NotificationPreferenceDetails.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/Paging.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/PaymentRequired.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/PreferenceStatus.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/RecipientPreferences.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/Rule.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/SingleTemplateTenantAssociation.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/TenantTemplateData.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/TenantTemplateDataNoContent.java
delete mode 100644 src/main/java/com/courier/api/resources/commons/types/UserTenantAssociation.java
delete mode 100644 src/main/java/com/courier/api/resources/inbound/InboundClient.java
delete mode 100644 src/main/java/com/courier/api/resources/inbound/types/InboundTrackEvent.java
delete mode 100644 src/main/java/com/courier/api/resources/inbound/types/TrackAcceptedResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/ListsClient.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/requests/AddSubscribersToList.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/requests/GetAllListsRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/requests/GetSubscriptionForListRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/requests/RestoreListRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/requests/SubscribeUserToListRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/requests/SubscribeUsersToListRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/types/List.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/types/ListGetAllResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/types/ListGetSubscriptionsResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/types/ListPutParams.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/types/ListSubscriptionRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/lists/types/PutSubscriptionsRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/MessagesClient.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/requests/GetMessageHistoryRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/requests/ListMessagesRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/types/IMessageDetails.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/types/ListMessagesResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/types/MessageDetails.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/types/MessageDetailsExtended.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/types/MessageHistoryResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/types/MessageStatus.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/types/Reason.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/types/RenderOutput.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/types/RenderOutputResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/types/RenderedMessageBlock.java
delete mode 100644 src/main/java/com/courier/api/resources/messages/types/RenderedMessageContent.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/NotificationsClient.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/requests/NotificationListParams.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/requests/SubmissionChecksReplaceParams.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/BaseCheck.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/BlockType.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/Check.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/CheckStatus.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/IBaseCheck.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/MessageRouting.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/MessageRoutingChannel.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/MessageRoutingMethod.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/Notification.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/NotificationBlock.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/NotificationChannel.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/NotificationChannelContent.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/NotificationContent.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/NotificationContentHierarchy.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/NotificationGetContentResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/NotificationListResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/NotificationTag.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/NotificationTagData.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/SubmissionChecksGetResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/notifications/types/SubmissionChecksReplaceResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/ProfilesClient.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/requests/GetListSubscriptionsRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/requests/MergeProfileRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/requests/ReplaceProfileRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/Address.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/AirshipProfile.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/AirshipProfileAudience.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/DeleteListSubscriptionResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/Discord.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/Expo.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/GetListSubscriptionsList.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/GetListSubscriptionsResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/IMsTeamsBaseProperties.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/ISlackBaseProperties.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/Intercom.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/IntercomRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/MergeProfileResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/MsTeams.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/MsTeamsBaseProperties.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/MultipleTokens.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/Pagerduty.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/ProfileGetParameters.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/ProfileGetResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/ProfileUpdateRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/ReplaceProfileResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SendDirectMessage.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SendToChannel.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SendToMsTeamsChannelId.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SendToMsTeamsChannelName.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SendToMsTeamsConversationId.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SendToMsTeamsEmail.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SendToMsTeamsUserId.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SendToSlackChannel.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SendToSlackEmail.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SendToSlackUserId.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/Slack.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SlackBaseProperties.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SnoozeRule.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SnoozeRuleType.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SubscribeToListsRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SubscribeToListsRequestListObject.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/SubscribeToListsResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/Token.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/UserProfile.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/UserProfileFirebaseToken.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/UserProfilePatch.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/WebhookAuthMode.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/WebhookAuthentication.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/WebhookMethod.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/WebhookProfile.java
delete mode 100644 src/main/java/com/courier/api/resources/profiles/types/WebhookProfileType.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/AudienceFilter.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/AudienceRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/BaseMessage.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/BaseMessageSendTo.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/BaseSocialPresence.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/BrandSettingsEmail.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/BrandSettingsInApp.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/BrandSettingsSocialPresence.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/BrandTemplate.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/BrandTemplateOverride.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Channel.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ChannelMetadata.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ChannelSource.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Content.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ContentMessage.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Criteria.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Delay.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalActionNode.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalBaseNode.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalChannelNode.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalContent.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalContentSugar.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalDividerNode.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalGroupNode.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalImageNode.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalMetaNode.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalNode.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalQuoteNode.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ElementalTextNode.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/EmailFooter.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/EmailHead.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/EmailHeader.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ExpiresInType.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Expiry.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/IActionButtonStyle.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/IAlignment.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/IBaseMessage.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/IBaseMessageSendTo.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/IBrandTemplate.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/IElementalBaseNode.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/IListPatternRecipientType.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/IListRecipientType.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/IProfilePreferences.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/IUserRecipientType.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Icons.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/InAppPlacement.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/InvalidListPatternRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/InvalidListRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/InvalidUserRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ListFilter.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ListPatternRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ListPatternRecipientType.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ListRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/ListRecipientType.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Locale.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Logo.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Message.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/MessageContext.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/MessageMetadata.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/MessagePreferences.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/MessageProvidersType.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/MessageRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Metadata.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/MsTeamsRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/PagerdutyRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Preference.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Preferences.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Recipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Routing.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/RoutingMethod.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/RuleType.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/SlackRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/TemplateMessage.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/TextAlign.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/TextStyle.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Timeout.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Timeouts.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/TrackingOverride.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/UserRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/UserRecipientType.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/Utm.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/WebhookRecipient.java
delete mode 100644 src/main/java/com/courier/api/resources/send/types/WidgetBackground.java
delete mode 100644 src/main/java/com/courier/api/resources/templates/TemplatesClient.java
delete mode 100644 src/main/java/com/courier/api/resources/templates/requests/ListTemplatesRequest.java
delete mode 100644 src/main/java/com/courier/api/resources/templates/types/ListTemplatesResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/templates/types/NotificationTemplates.java
delete mode 100644 src/main/java/com/courier/api/resources/templates/types/RoutingStrategy.java
delete mode 100644 src/main/java/com/courier/api/resources/templates/types/RoutingStrategyMethod.java
delete mode 100644 src/main/java/com/courier/api/resources/templates/types/Tag.java
delete mode 100644 src/main/java/com/courier/api/resources/templates/types/TagData.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/TenantsClient.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/requests/GetTemplateListByTenantParams.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/requests/ListTenantParams.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/requests/ListUsersForTenantParams.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/requests/TenantCreateOrReplaceParams.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/types/DefaultPreferences.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/types/GetTemplateByTenantResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/types/ISubscriptionTopicNew.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/types/ListTemplatesByTenantResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/types/ListUsersForTenantResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/types/SubscriptionTopic.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/types/SubscriptionTopicNew.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/types/SubscriptionTopicStatus.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/types/Tenant.java
delete mode 100644 src/main/java/com/courier/api/resources/tenants/types/TenantListResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/translations/TranslationsClient.java
delete mode 100644 src/main/java/com/courier/api/resources/users/UsersClient.java
delete mode 100644 src/main/java/com/courier/api/resources/users/preferences/PreferencesClient.java
delete mode 100644 src/main/java/com/courier/api/resources/users/preferences/requests/UserPreferencesParams.java
delete mode 100644 src/main/java/com/courier/api/resources/users/preferences/requests/UserPreferencesTopicParams.java
delete mode 100644 src/main/java/com/courier/api/resources/users/preferences/requests/UserPreferencesUpdateParams.java
delete mode 100644 src/main/java/com/courier/api/resources/users/preferences/types/TopicPreference.java
delete mode 100644 src/main/java/com/courier/api/resources/users/preferences/types/TopicPreferenceUpdate.java
delete mode 100644 src/main/java/com/courier/api/resources/users/preferences/types/UserPreferencesGetResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/users/preferences/types/UserPreferencesListResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/users/preferences/types/UserPreferencesUpdateResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tenants/TenantsClient.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tenants/requests/AddUserToMultipleTenantsParams.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tenants/requests/AddUserToSingleTenantsParams.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tenants/requests/ListTenantsForUserParams.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tenants/types/AddUserToSingleTenantsParamsProfile.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tenants/types/ListTenantsForUserResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/TokensClient.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/DeleteUserTokenOpts.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/Device.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/ExpiryDate.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/GetUserTokenOpts.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/GetUserTokenResponse.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/GetUserTokensOpts.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/IUserToken.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/PatchOp.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/PatchOperation.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/PatchUserTokenOpts.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/ProviderKey.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/PutUserTokenOpts.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/PutUserTokensOpts.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/TokenStatus.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/Tracking.java
delete mode 100644 src/main/java/com/courier/api/resources/users/tokens/types/UserToken.java
delete mode 100644 src/main/java/com/courier/api/types/SendMessageResponse.java
delete mode 100644 src/test/java/com/courier/api/TestClient.java
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 00000000..bd8e2619
--- /dev/null
+++ b/.devcontainer/Dockerfile
@@ -0,0 +1,23 @@
+# syntax=docker/dockerfile:1
+FROM debian:bookworm-slim
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ libxkbcommon0 \
+ ca-certificates \
+ ca-certificates-java \
+ make \
+ curl \
+ git \
+ openjdk-17-jdk-headless \
+ unzip \
+ libc++1 \
+ vim \
+ && apt-get clean autoclean
+
+# Ensure UTF-8 encoding
+ENV LANG=C.UTF-8
+ENV LC_ALL=C.UTF-8
+
+WORKDIR /workspace
+
+COPY . /workspace
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 00000000..d55fc4d6
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,20 @@
+// For format details, see https://aka.ms/devcontainer.json. For config options, see the
+// README at: https://github.com/devcontainers/templates/tree/main/src/debian
+{
+ "name": "Debian",
+ "build": {
+ "dockerfile": "Dockerfile"
+ }
+
+ // Features to add to the dev container. More info: https://containers.dev/features.
+ // "features": {},
+
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ // "forwardPorts": [],
+
+ // Configure tool-specific properties.
+ // "customizations": {},
+
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+ // "remoteUser": "root"
+}
diff --git a/.fernignore b/.fernignore
deleted file mode 100644
index 793636f0..00000000
--- a/.fernignore
+++ /dev/null
@@ -1,4 +0,0 @@
-# Specify files that shouldn't be modified by Fern
-
-LICENSE
-README.md
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..022b8414
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,5 @@
+#
+# https://help.github.com/articles/dealing-with-line-endings/
+#
+# These are explicitly windows files and should use crlf
+*.bat text eol=crlf
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2e52af1f..f668ddf3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,65 +1,85 @@
-name: ci
-
-on: [push]
+name: CI
+on:
+ push:
+ branches-ignore:
+ - 'generated'
+ - 'codegen/**'
+ - 'integrated/**'
+ - 'stl-preview-head/**'
+ - 'stl-preview-base/**'
+ pull_request:
+ branches-ignore:
+ - 'stl-preview-head/**'
+ - 'stl-preview-base/**'
jobs:
- compile:
- runs-on: ubuntu-latest
+ lint:
+ timeout-minutes: 15
+ name: lint
+ runs-on: ${{ github.repository == 'stainless-sdks/courier-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
+ if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- - name: Checkout repo
- uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Java
- id: setup-jre
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v4
with:
- java-version: "11"
- architecture: x64
+ distribution: temurin
+ java-version: |
+ 8
+ 21
+ cache: gradle
- - name: Compile
- run: ./gradlew compileJava
+ - name: Set up Gradle
+ uses: gradle/actions/setup-gradle@v4
+
+ - name: Run lints
+ run: ./scripts/lint
+
+ build:
+ timeout-minutes: 15
+ name: build
+ runs-on: ${{ github.repository == 'stainless-sdks/courier-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
+ if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
- test:
- needs: [ compile ]
- runs-on: ubuntu-latest
steps:
- - name: Checkout repo
- uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Java
- id: setup-jre
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v4
with:
- java-version: "11"
- architecture: x64
+ distribution: temurin
+ java-version: |
+ 8
+ 21
+ cache: gradle
- - name: Test
- run: ./gradlew test
- publish:
- needs: [ compile, test ]
- if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
- runs-on: ubuntu-latest
+ - name: Set up Gradle
+ uses: gradle/actions/setup-gradle@v4
+ - name: Build SDK
+ run: ./scripts/build
+
+ test:
+ timeout-minutes: 15
+ name: test
+ runs-on: ${{ github.repository == 'stainless-sdks/courier-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
+ if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- - name: Checkout repo
- uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Java
- id: setup-jre
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v4
with:
- java-version: "11"
- architecture: x64
+ distribution: temurin
+ java-version: |
+ 8
+ 21
+ cache: gradle
+
+ - name: Set up Gradle
+ uses: gradle/gradle-build-action@v2
- - name: Publish to maven
- run: |
- ./.publish/prepare.sh
- ./gradlew publish
- env:
- MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
- MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
- MAVEN_PUBLISH_REGISTRY_URL: "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
- MAVEN_SIGNATURE_KID: ${{ secrets.MAVEN_SIGNATURE_KID }}
- MAVEN_SIGNATURE_SECRET_KEY: ${{ secrets.MAVEN_SIGNATURE_SECRET_KEY }}
- MAVEN_SIGNATURE_PASSWORD: ${{ secrets.MAVEN_SIGNATURE_PASSWORD }}
+ - name: Run tests
+ run: ./scripts/test
diff --git a/.gitignore b/.gitignore
index d4199abc..b1346e6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,24 +1,7 @@
-*.class
-.project
+.prism.log
.gradle
-?
-.classpath
-.checkstyle
-.settings
-.node
-build
-
-# IntelliJ
-*.iml
-*.ipr
-*.iws
-.idea/
-out/
-
-# Eclipse/IntelliJ APT
-generated_src/
-generated_testSrc/
-generated/
-
-bin
-build
\ No newline at end of file
+.idea
+.kotlin
+build/
+codegen.log
+kls_database.db
diff --git a/.publish/prepare.sh b/.publish/prepare.sh
deleted file mode 100755
index df3948e3..00000000
--- a/.publish/prepare.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-# Write key ring file
-echo "$MAVEN_SIGNATURE_SECRET_KEY" > armored_key.asc
-gpg -o publish_key.gpg --dearmor armored_key.asc
-
-# Generate gradle.properties file
-echo "signing.keyId=$MAVEN_SIGNATURE_KID" > gradle.properties
-echo "signing.secretKeyRingFile=publish_key.gpg" >> gradle.properties
-echo "signing.password=$MAVEN_SIGNATURE_PASSWORD" >> gradle.properties
diff --git a/.stats.yml b/.stats.yml
new file mode 100644
index 00000000..a30affc9
--- /dev/null
+++ b/.stats.yml
@@ -0,0 +1,4 @@
+configured_endpoints: 75
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier%2Fcourier-9edfa04d0cd081138f4834ed9b8d45403d7ee75a5f02f8eecc8e45575df21bb8.yml
+openapi_spec_hash: 195e8cd1061046ffc3009f50262d92b2
+config_hash: cdd0e8b97754393a5262fb5e52e2ddcf
diff --git a/LICENSE b/LICENSE
index d82d2ea7..efaa7fe8 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,201 @@
-MIT License
-
-Copyright (c) 2020 Courier
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
\ No newline at end of file
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2025 Courier
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.md b/README.md
index 60ee7d22..cb8be759 100644
--- a/README.md
+++ b/README.md
@@ -1,149 +1,653 @@
-# Courier Java Library
+# Courier Java API Library
-[](https://central.sonatype.com/artifact/com.courier/courier-java)
-[](https://buildwithfern.com/?utm_source=trycourier/courier-java/readme)
+[](https://central.sonatype.com/artifact/com.courier.api/courier-java/0.0.1)
+[](https://javadoc.io/doc/com.courier.api/courier-java/0.0.1)
-This is the official Java library for sending notifications with the [Courier](https://courier.com) REST API.
+The Courier Java SDK provides convenient access to the Courier REST API from applications written in Java.
-## Documentation
+It is generated with [Stainless](https://www.stainless.com/).
-For a full description of request and response payloads and properties, please see the
-[official Courier API docs](https://www.courier.com/docs/reference/).
-
-## Requirements
-
-This library requires Java 11+.
+Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.courier.api/courier-java/0.0.1).
## Installation
### Gradle
-Add the dependency in your `build.gradle`:
-
-```groovy
-dependencies {
- implementation 'com.courier:courier-java:x.x.x'
-}
+```kotlin
+implementation("com.courier.api:courier-java:0.0.1")
```
### Maven
-Add the dependency in your `pom.xml`:
-
```xml
- com.courier
- courier-java
- 0.x.x
+ com.courier.api
+ courier-java
+ 0.0.1
```
+## Requirements
+
+This library requires Java 8 or later.
+
## Usage
-Below is an example of how to instantiate the Courier client
-and send a message.
```java
-import com.courier.api.Courier;
+import com.courier.api.client.CourierClient;
+import com.courier.api.client.okhttp.CourierOkHttpClient;
+import com.courier.api.models.send.Content;
+import com.courier.api.models.send.ElementalNode;
+import com.courier.api.models.send.Message;
+import com.courier.api.models.send.SendSendMessageParams;
+import com.courier.api.models.send.SendSendMessageResponse;
+
+// Configures using the `courier.apiKey` and `courier.baseUrl` system properties
+// Or configures using the `COURIER_API_KEY` and `COURIER_BASE_URL` environment variables
+CourierClient client = CourierOkHttpClient.fromEnv();
+
+SendSendMessageParams params = SendSendMessageParams.builder()
+ .message(Message.ContentMessage.builder()
+ .content(Content.ElementalContent.builder()
+ .addElement(ElementalNode.UnionMember0.builder().build())
+ .version("version")
+ .build())
+ .build())
+ .build();
+SendSendMessageResponse response = client.send().sendMessage(params);
+```
+
+## Client configuration
+
+Configure the client using system properties or environment variables:
-Courier courier = Courier.builder()
- .authorizationToken("YOUR_TOKEN") # Defaults to System.getenv("COURIER_AUTHORIZATION_TOKEN")
+```java
+import com.courier.api.client.CourierClient;
+import com.courier.api.client.okhttp.CourierOkHttpClient;
+
+// Configures using the `courier.apiKey` and `courier.baseUrl` system properties
+// Or configures using the `COURIER_API_KEY` and `COURIER_BASE_URL` environment variables
+CourierClient client = CourierOkHttpClient.fromEnv();
+```
+
+Or manually:
+
+```java
+import com.courier.api.client.CourierClient;
+import com.courier.api.client.okhttp.CourierOkHttpClient;
+
+CourierClient client = CourierOkHttpClient.builder()
+ .apiKey("My API Key")
.build();
+```
+
+Or using a combination of the two approaches:
-courier.send(SendMessageRequest.builder()
- .message(Message.of(TemplateMessage.builder()
- .template("")
- .to(MessageRecipient.of(Recipient.of(UserRecipient.builder()
- .email("marty_mcfly@email.com")
- .build())))
- .build()))
- .build());
+```java
+import com.courier.api.client.CourierClient;
+import com.courier.api.client.okhttp.CourierOkHttpClient;
+
+CourierClient client = CourierOkHttpClient.builder()
+ // Configures using the `courier.apiKey` and `courier.baseUrl` system properties
+ // Or configures using the `COURIER_API_KEY` and `COURIER_BASE_URL` environment variables
+ .fromEnv()
+ .apiKey("My API Key")
+ .build();
```
-## Upgrade Guides
+See this table for the available options:
+
+| Setter | System property | Environment variable | Required | Default value |
+| --------- | ----------------- | -------------------- | -------- | --------------------------- |
+| `apiKey` | `courier.apiKey` | `COURIER_API_KEY` | true | - |
+| `baseUrl` | `courier.baseUrl` | `COURIER_BASE_URL` | true | `"https://api.courier.com"` |
-### v2 to v3
+System properties take precedence over environment variables.
-v3 of our SDK is automatically generated by [Fern](https://buildwithfern.com/). v3 comes
-with several improvements that we describe below:
+> [!TIP]
+> Don't create more than one client in the same application. Each client has a connection pool and
+> thread pools, which are more efficient to share between requests.
-- **Resource-scoped SDK methods**: Endpoints are scoped under their resource. For
- example, instead of `courier.deleteBrands` the SDK now reads `courier.brands.delete(...)`
-- **Docs on Hover**: All endpoint and parameter level documentation that you see
- on our docs website is now embedded directly within the SDKs.
-- **Retries with exponential backoff**: The SDK will automatically retry failures with
- exponential backoff.
-- **Strongly Typed**: The SDK has Java objects to describe each of our request and
- response models. Each object has a static `builder` method and uses the staged
- builder pattern.
- ```java
- UserRecipient.builder()
- .email("marty_mcfly@email.com")
- .build();
- ```
-- **Unions** The SDK has natively supports unions. Every union is modelled as a java
- class that has static factory methods.
- ```java
- // Message has static factory methods that either take a TemplateMessage or
- // ContentMessage
- Message.of(TemplateMessage.builder()...)
-
- Message.of(ContentMessage.builder()...)
- ```
+### Modifying configuration
-## Request Options
-Every endpoint has an overloaded equivalent which takes [RequestOptions](./src/main/java/com/courier/api/core/RequestOptions.java)
-that allow you to override settings for that particular request.
+To temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service:
```java
-import com.courier.api.Courier;
+import com.courier.api.client.CourierClient;
-courier.brands.get(..., RequestOptions.builder()
- .authorizationToken(...)
- .build())
+CourierClient clientWithOptions = client.withOptions(optionsBuilder -> {
+ optionsBuilder.baseUrl("https://example.com");
+ optionsBuilder.maxRetries(42);
+});
```
-## Idempotency Headers
-You can specify idempotency headers by providing an `IdempotentRequestOptions` parameter.
+The `withOptions()` method does not affect the original client or service.
+
+## Requests and responses
+
+To send a request to the Courier API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class.
+
+For example, `client.send().sendMessage(...)` should be called with an instance of `SendSendMessageParams`, and it will return an instance of `SendSendMessageResponse`.
+
+## Immutability
+
+Each class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it.
+
+Each class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy.
+
+Because each class is immutable, builder modification will _never_ affect already built class instances.
+
+## Asynchronous execution
+
+The default client is synchronous. To switch to asynchronous execution, call the `async()` method:
+
+```java
+import com.courier.api.client.CourierClient;
+import com.courier.api.client.okhttp.CourierOkHttpClient;
+import com.courier.api.models.send.Content;
+import com.courier.api.models.send.ElementalNode;
+import com.courier.api.models.send.Message;
+import com.courier.api.models.send.SendSendMessageParams;
+import com.courier.api.models.send.SendSendMessageResponse;
+import java.util.concurrent.CompletableFuture;
+
+// Configures using the `courier.apiKey` and `courier.baseUrl` system properties
+// Or configures using the `COURIER_API_KEY` and `COURIER_BASE_URL` environment variables
+CourierClient client = CourierOkHttpClient.fromEnv();
+
+SendSendMessageParams params = SendSendMessageParams.builder()
+ .message(Message.ContentMessage.builder()
+ .content(Content.ElementalContent.builder()
+ .addElement(ElementalNode.UnionMember0.builder().build())
+ .version("version")
+ .build())
+ .build())
+ .build();
+CompletableFuture response = client.async().send().sendMessage(params);
+```
+
+Or create an asynchronous client from the beginning:
+
+```java
+import com.courier.api.client.CourierClientAsync;
+import com.courier.api.client.okhttp.CourierOkHttpClientAsync;
+import com.courier.api.models.send.Content;
+import com.courier.api.models.send.ElementalNode;
+import com.courier.api.models.send.Message;
+import com.courier.api.models.send.SendSendMessageParams;
+import com.courier.api.models.send.SendSendMessageResponse;
+import java.util.concurrent.CompletableFuture;
+
+// Configures using the `courier.apiKey` and `courier.baseUrl` system properties
+// Or configures using the `COURIER_API_KEY` and `COURIER_BASE_URL` environment variables
+CourierClientAsync client = CourierOkHttpClientAsync.fromEnv();
+
+SendSendMessageParams params = SendSendMessageParams.builder()
+ .message(Message.ContentMessage.builder()
+ .content(Content.ElementalContent.builder()
+ .addElement(ElementalNode.UnionMember0.builder().build())
+ .version("version")
+ .build())
+ .build())
+ .build();
+CompletableFuture response = client.send().sendMessage(params);
+```
+
+The asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s.
+
+## Raw responses
+
+The SDK defines methods that deserialize responses into instances of Java classes. However, these methods don't provide access to the response headers, status code, or the raw response body.
+
+To access this data, prefix any HTTP method call on a client or service with `withRawResponse()`:
```java
-import com.courier.api.Courier;
-import java.util.UUID;
+import com.courier.api.core.http.Headers;
+import com.courier.api.core.http.HttpResponseFor;
+import com.courier.api.models.send.Content;
+import com.courier.api.models.send.ElementalNode;
+import com.courier.api.models.send.Message;
+import com.courier.api.models.send.SendSendMessageParams;
+import com.courier.api.models.send.SendSendMessageResponse;
+
+SendSendMessageParams params = SendSendMessageParams.builder()
+ .message(Message.ContentMessage.builder()
+ .content(Content.ElementalContent.builder()
+ .addElement(ElementalNode.UnionMember0.builder().build())
+ .version("version")
+ .build())
+ .build())
+ .build();
+HttpResponseFor response = client.send().withRawResponse().sendMessage(params);
-courier.send(..., IdempotentRequestOptions.builder()
- .idempotencyKey(UUID.randomUUID().toString())
- .build())
+int statusCode = response.statusCode();
+Headers headers = response.headers();
```
-## Exception Handling
-All errors thrown by the SDK will be subclasses of `com.courier.api.APIError`.
+You can still deserialize the response into an instance of a Java class if needed:
```java
-import com.courier.api.core.ApiError;
+import com.courier.api.models.send.SendSendMessageResponse;
-try {
- courier.brands.get(...)
-} catch (ApiError e) {
- System.out.println(e.statusCode());
- System.out.println(e.body());
+SendSendMessageResponse parsedResponse = response.parse();
+```
+
+## Error handling
+
+The SDK throws custom unchecked exception types:
+
+- [`CourierServiceException`](courier-java-core/src/main/kotlin/com/courier/api/errors/CourierServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code:
+
+ | Status | Exception |
+ | ------ | ---------------------------------------------------------------------------------------------------------------------------- |
+ | 400 | [`BadRequestException`](courier-java-core/src/main/kotlin/com/courier/api/errors/BadRequestException.kt) |
+ | 401 | [`UnauthorizedException`](courier-java-core/src/main/kotlin/com/courier/api/errors/UnauthorizedException.kt) |
+ | 403 | [`PermissionDeniedException`](courier-java-core/src/main/kotlin/com/courier/api/errors/PermissionDeniedException.kt) |
+ | 404 | [`NotFoundException`](courier-java-core/src/main/kotlin/com/courier/api/errors/NotFoundException.kt) |
+ | 422 | [`UnprocessableEntityException`](courier-java-core/src/main/kotlin/com/courier/api/errors/UnprocessableEntityException.kt) |
+ | 429 | [`RateLimitException`](courier-java-core/src/main/kotlin/com/courier/api/errors/RateLimitException.kt) |
+ | 5xx | [`InternalServerException`](courier-java-core/src/main/kotlin/com/courier/api/errors/InternalServerException.kt) |
+ | others | [`UnexpectedStatusCodeException`](courier-java-core/src/main/kotlin/com/courier/api/errors/UnexpectedStatusCodeException.kt) |
+
+- [`CourierIoException`](courier-java-core/src/main/kotlin/com/courier/api/errors/CourierIoException.kt): I/O networking errors.
+
+- [`CourierRetryableException`](courier-java-core/src/main/kotlin/com/courier/api/errors/CourierRetryableException.kt): Generic error indicating a failure that could be retried by the client.
+
+- [`CourierInvalidDataException`](courier-java-core/src/main/kotlin/com/courier/api/errors/CourierInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response.
+
+- [`CourierException`](courier-java-core/src/main/kotlin/com/courier/api/errors/CourierException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.
+
+## Logging
+
+The SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor).
+
+Enable logging by setting the `COURIER_LOG` environment variable to `info`:
+
+```sh
+$ export COURIER_LOG=info
+```
+
+Or to `debug` for more verbose logging:
+
+```sh
+$ export COURIER_LOG=debug
+```
+
+## ProGuard and R8
+
+Although the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `courier-java-core` is published with a [configuration file](courier-java-core/src/main/resources/META-INF/proguard/courier-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).
+
+ProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary.
+
+## Jackson
+
+The SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default.
+
+The SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config).
+
+If the SDK threw an exception, but you're _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`CourierOkHttpClient`](courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClient.kt) or [`CourierOkHttpClientAsync`](courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClientAsync.kt).
+
+> [!CAUTION]
+> We make no guarantee that the SDK works correctly when the Jackson version check is disabled.
+
+## Network options
+
+### Retries
+
+The SDK automatically retries 2 times by default, with a short exponential backoff between requests.
+
+Only the following error types are retried:
+
+- Connection errors (for example, due to a network connectivity problem)
+- 408 Request Timeout
+- 409 Conflict
+- 429 Rate Limit
+- 5xx Internal
+
+The API may also explicitly instruct the SDK to retry or not retry a request.
+
+To set a custom number of retries, configure the client using the `maxRetries` method:
+
+```java
+import com.courier.api.client.CourierClient;
+import com.courier.api.client.okhttp.CourierOkHttpClient;
+
+CourierClient client = CourierOkHttpClient.builder()
+ .fromEnv()
+ .maxRetries(4)
+ .build();
+```
+
+### Timeouts
+
+Requests time out after 1 minute by default.
+
+To set a custom timeout, configure the method call using the `timeout` method:
+
+```java
+import com.courier.api.models.send.SendSendMessageResponse;
+
+SendSendMessageResponse response = client.send().sendMessage(
+ params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build()
+);
+```
+
+Or configure the default for all method calls at the client level:
+
+```java
+import com.courier.api.client.CourierClient;
+import com.courier.api.client.okhttp.CourierOkHttpClient;
+import java.time.Duration;
+
+CourierClient client = CourierOkHttpClient.builder()
+ .fromEnv()
+ .timeout(Duration.ofSeconds(30))
+ .build();
+```
+
+### Proxies
+
+To route requests through a proxy, configure the client using the `proxy` method:
+
+```java
+import com.courier.api.client.CourierClient;
+import com.courier.api.client.okhttp.CourierOkHttpClient;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+
+CourierClient client = CourierOkHttpClient.builder()
+ .fromEnv()
+ .proxy(new Proxy(
+ Proxy.Type.HTTP, new InetSocketAddress(
+ "https://example.com", 8080
+ )
+ ))
+ .build();
+```
+
+### HTTPS
+
+> [!NOTE]
+> Most applications should not call these methods, and instead use the system defaults. The defaults include
+> special optimizations that can be lost if the implementations are modified.
+
+To configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:
+
+```java
+import com.courier.api.client.CourierClient;
+import com.courier.api.client.okhttp.CourierOkHttpClient;
+
+CourierClient client = CourierOkHttpClient.builder()
+ .fromEnv()
+ // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.
+ .sslSocketFactory(yourSSLSocketFactory)
+ .trustManager(yourTrustManager)
+ .hostnameVerifier(yourHostnameVerifier)
+ .build();
+```
+
+### Custom HTTP client
+
+The SDK consists of three artifacts:
+
+- `courier-java-core`
+ - Contains core SDK logic
+ - Does not depend on [OkHttp](https://square.github.io/okhttp)
+ - Exposes [`CourierClient`](courier-java-core/src/main/kotlin/com/courier/api/client/CourierClient.kt), [`CourierClientAsync`](courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsync.kt), [`CourierClientImpl`](courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientImpl.kt), and [`CourierClientAsyncImpl`](courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsyncImpl.kt), all of which can work with any HTTP client
+- `courier-java-client-okhttp`
+ - Depends on [OkHttp](https://square.github.io/okhttp)
+ - Exposes [`CourierOkHttpClient`](courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClient.kt) and [`CourierOkHttpClientAsync`](courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClientAsync.kt), which provide a way to construct [`CourierClientImpl`](courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientImpl.kt) and [`CourierClientAsyncImpl`](courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsyncImpl.kt), respectively, using OkHttp
+- `courier-java`
+ - Depends on and exposes the APIs of both `courier-java-core` and `courier-java-client-okhttp`
+ - Does not have its own logic
+
+This structure allows replacing the SDK's default HTTP client without pulling in unnecessary dependencies.
+
+#### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html)
+
+> [!TIP]
+> Try the available [network options](#network-options) before replacing the default client.
+
+To use a customized `OkHttpClient`:
+
+1. Replace your [`courier-java` dependency](#installation) with `courier-java-core`
+2. Copy `courier-java-client-okhttp`'s [`OkHttpClient`](courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/OkHttpClient.kt) class into your code and customize it
+3. Construct [`CourierClientImpl`](courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientImpl.kt) or [`CourierClientAsyncImpl`](courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsyncImpl.kt), similarly to [`CourierOkHttpClient`](courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClient.kt) or [`CourierOkHttpClientAsync`](courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClientAsync.kt), using your customized client
+
+### Completely custom HTTP client
+
+To use a completely custom HTTP client:
+
+1. Replace your [`courier-java` dependency](#installation) with `courier-java-core`
+2. Write a class that implements the [`HttpClient`](courier-java-core/src/main/kotlin/com/courier/api/core/http/HttpClient.kt) interface
+3. Construct [`CourierClientImpl`](courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientImpl.kt) or [`CourierClientAsyncImpl`](courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsyncImpl.kt), similarly to [`CourierOkHttpClient`](courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClient.kt) or [`CourierOkHttpClientAsync`](courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClientAsync.kt), using your new client class
+
+## Undocumented API functionality
+
+The SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API.
+
+### Parameters
+
+To set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class:
+
+```java
+import com.courier.api.core.JsonValue;
+import com.courier.api.models.send.SendSendMessageParams;
+
+SendSendMessageParams params = SendSendMessageParams.builder()
+ .putAdditionalHeader("Secret-Header", "42")
+ .putAdditionalQueryParam("secret_query_param", "42")
+ .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))
+ .build();
+```
+
+These can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods.
+
+To set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class:
+
+```java
+import com.courier.api.core.JsonValue;
+import com.courier.api.models.automations.AutomationInvokeAdHocParams;
+
+AutomationInvokeAdHocParams params = AutomationInvokeAdHocParams.builder()
+ .automation(AutomationInvokeAdHocParams.Automation.builder()
+ .putAdditionalProperty("secretProperty", JsonValue.from("42"))
+ .build())
+ .build();
+```
+
+These properties can be accessed on the nested built object later using the `_additionalProperties()` method.
+
+To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](courier-java-core/src/main/kotlin/com/courier/api/core/Values.kt) object to its setter:
+
+```java
+import com.courier.api.core.JsonValue;
+import com.courier.api.models.send.SendSendMessageParams;
+
+SendSendMessageParams params = SendSendMessageParams.builder()
+ .message(JsonValue.from(42))
+ .build();
+```
+
+The most straightforward way to create a [`JsonValue`](courier-java-core/src/main/kotlin/com/courier/api/core/Values.kt) is using its `from(...)` method:
+
+```java
+import com.courier.api.core.JsonValue;
+import java.util.List;
+import java.util.Map;
+
+// Create primitive JSON values
+JsonValue nullValue = JsonValue.from(null);
+JsonValue booleanValue = JsonValue.from(true);
+JsonValue numberValue = JsonValue.from(42);
+JsonValue stringValue = JsonValue.from("Hello World!");
+
+// Create a JSON array value equivalent to `["Hello", "World"]`
+JsonValue arrayValue = JsonValue.from(List.of(
+ "Hello", "World"
+));
+
+// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }`
+JsonValue objectValue = JsonValue.from(Map.of(
+ "a", 1,
+ "b", 2
+));
+
+// Create an arbitrarily nested JSON equivalent to:
+// {
+// "a": [1, 2],
+// "b": [3, 4]
+// }
+JsonValue complexValue = JsonValue.from(Map.of(
+ "a", List.of(
+ 1, 2
+ ),
+ "b", List.of(
+ 3, 4
+ )
+));
+```
+
+Normally a `Builder` class's `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset.
+
+To forcibly omit a required parameter or property, pass [`JsonMissing`](courier-java-core/src/main/kotlin/com/courier/api/core/Values.kt):
+
+```java
+import com.courier.api.core.JsonMissing;
+import com.courier.api.models.send.SendSendMessageParams;
+
+SendSendMessageParams params = SendSendMessageParams.builder()
+ .message(JsonMissing.of())
+ .build();
+```
+
+### Response properties
+
+To access undocumented response properties, call the `_additionalProperties()` method:
+
+```java
+import com.courier.api.core.JsonValue;
+import java.util.Map;
+
+Map additionalProperties = client.send().sendMessage(params)._additionalProperties();
+JsonValue secretPropertyValue = additionalProperties.get("secretProperty");
+
+String result = secretPropertyValue.accept(new JsonValue.Visitor<>() {
+ @Override
+ public String visitNull() {
+ return "It's null!";
+ }
+
+ @Override
+ public String visitBoolean(boolean value) {
+ return "It's a boolean!";
+ }
+
+ @Override
+ public String visitNumber(Number value) {
+ return "It's a number!";
+ }
+
+ // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject`
+ // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden
+});
+```
+
+To access a property's raw JSON value, which may be undocumented, call its `_` prefixed method:
+
+```java
+import com.courier.api.core.JsonField;
+import com.courier.api.models.send.Message;
+import java.util.Optional;
+
+JsonField message = client.send().sendMessage(params)._message();
+
+if (message.isMissing()) {
+ // The property is absent from the JSON response
+} else if (message.isNull()) {
+ // The property was set to literal null
+} else {
+ // Check if value was provided as a string
+ // Other methods include `asNumber()`, `asBoolean()`, etc.
+ Optional jsonString = message.asString();
+
+ // Try to deserialize into a custom type
+ MyClass myObject = message.asUnknown().orElseThrow().convert(MyClass.class);
}
```
-## Retries
-409 Conflict, 429 Rate Limit, and >=500 Internal errors will all be retried twice
-with exponential backoff.
+### Response validation
+
+In rare cases, the API may return a response that doesn't match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else.
+
+By default, the SDK will not throw an exception in this case. It will throw [`CourierInvalidDataException`](courier-java-core/src/main/kotlin/com/courier/api/errors/CourierInvalidDataException.kt) only if you directly access the property.
+
+If you would prefer to check that the response is completely well-typed upfront, then either call `validate()`:
+
+```java
+import com.courier.api.models.send.SendSendMessageResponse;
+
+SendSendMessageResponse response = client.send().sendMessage(params).validate();
+```
+
+Or configure the method call to validate the response using the `responseValidation` method:
+
+```java
+import com.courier.api.models.send.SendSendMessageResponse;
+
+SendSendMessageResponse response = client.send().sendMessage(
+ params, RequestOptions.builder().responseValidation(true).build()
+);
+```
-## Additional Properties
-Sometimes, the server response may include additional properties that are not
-available in the SDK. Use the `getAdditionalProperties()` method to access them.
+Or configure the default for all method calls at the client level:
```java
-Object value = entity.getAdditionalProperties().get("new_prop");
+import com.courier.api.client.CourierClient;
+import com.courier.api.client.okhttp.CourierOkHttpClient;
+
+CourierClient client = CourierOkHttpClient.builder()
+ .fromEnv()
+ .responseValidation(true)
+ .build();
```
-## Contributing
-While we value open-source contributions to this SDK, this library is generated programmatically.
-Additions made directly to this library would have to be moved over to our generation code, otherwise
-they would be overwritten upon the next generated release. Feel free to open a PR as a proof of concept,
-but know that we will not be able to merge it as-is. We suggest opening an issue first to discuss with us!
+## FAQ
+
+### Why don't you use plain `enum` classes?
+
+Java `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value.
+
+### Why do you represent fields using `JsonField` instead of just plain `T`?
+
+Using `JsonField` enables a few features:
+
+- Allowing usage of [undocumented API functionality](#undocumented-api-functionality)
+- Lazily [validating the API response against the expected shape](#response-validation)
+- Representing absent vs explicitly null values
+
+### Why don't you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)?
+
+It is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don't want to introduce a breaking change every time we add a field to a class.
+
+### Why don't you use checked exceptions?
+
+Checked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason.
+
+Checked exceptions:
+
+- Are verbose to handle
+- Encourage error handling at the wrong level of abstraction, where nothing can be done about the error
+- Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function)
+- Don't play well with lambdas (also due to the function coloring problem)
+
+## Semantic versioning
+
+This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
+
+1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_
+2. Changes that we do not expect to impact the vast majority of users in practice.
+
+We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
-On the other hand, contributions to the README are always very welcome!
\ No newline at end of file
+We are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/courier-java/issues) with questions, bugs, or suggestions.
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 00000000..e8a2e774
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,23 @@
+# Security Policy
+
+## Reporting Security Issues
+
+This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken.
+
+To report a security issue, please contact the Stainless team at security@stainless.com.
+
+## Responsible Disclosure
+
+We appreciate the efforts of security researchers and individuals who help us maintain the security of
+SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible
+disclosure practices by allowing us a reasonable amount of time to investigate and address the issue
+before making any information public.
+
+## Reporting Non-SDK Related Security Issues
+
+If you encounter security issues that are not directly related to SDKs but pertain to the services
+or products provided by Courier, please follow the respective company's security reporting guidelines.
+
+---
+
+Thank you for helping us keep the SDKs and systems they interact with secure.
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index 2154b2e1..00000000
--- a/build.gradle
+++ /dev/null
@@ -1,88 +0,0 @@
-plugins {
- id 'java-library'
- id 'maven-publish'
- id 'com.diffplug.spotless' version '6.11.0'
- id 'signing'
-}
-
-repositories {
- mavenCentral()
- maven {
- url 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'
- }
-}
-
-dependencies {
- api 'com.squareup.okhttp3:okhttp:4.12.0'
- api 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
- api 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.12.3'
- api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3'
- testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
- testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
-}
-
-
-sourceCompatibility = 1.8
-targetCompatibility = 1.8
-
-spotless {
- java {
- palantirJavaFormat()
- }
-}
-
-java {
- withSourcesJar()
- withJavadocJar()
-}
-
-signing {
- sign(publishing.publications)
-}
-test {
- useJUnitPlatform()
- testLogging {
- showStandardStreams = true
- }
-}
-publishing {
- publications {
- maven(MavenPublication) {
- groupId = 'com.courier'
- artifactId = 'courier-java'
- version = '3.6.0'
- from components.java
- pom {
- name = 'courier'
- description = 'The official Java library for sending notifications with the Courier REST API.'
- url = 'https://www.courier.com/docs/reference/'
- licenses {
- license {
- name = 'MIT'
- }
- }
- developers {
- developer {
- name = 'courier'
- email = 'developers@courier.com'
- }
- }
- scm {
- connection = 'scm:git:git://github.com/trycourier/courier-java.git'
- developerConnection = 'scm:git:git://github.com/trycourier/courier-java.git'
- url = 'https://github.com/trycourier/courier-java'
- }
- }
- }
- }
- repositories {
- maven {
- url "$System.env.MAVEN_PUBLISH_REGISTRY_URL"
- credentials {
- username "$System.env.MAVEN_USERNAME"
- password "$System.env.MAVEN_PASSWORD"
- }
- }
- }
-}
-
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 00000000..4170b798
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,49 @@
+plugins {
+ id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
+ id("org.jetbrains.dokka") version "2.0.0"
+}
+
+repositories {
+ mavenCentral()
+}
+
+allprojects {
+ group = "com.courier.api"
+ version = "0.0.1"
+}
+
+subprojects {
+ // These are populated with dependencies by `buildSrc` scripts.
+ tasks.register("format") {
+ group = "Verification"
+ description = "Formats all source files."
+ }
+ tasks.register("lint") {
+ group = "Verification"
+ description = "Verifies all source files are formatted."
+ }
+ apply(plugin = "org.jetbrains.dokka")
+}
+
+subprojects {
+ apply(plugin = "org.jetbrains.dokka")
+}
+
+// Avoid race conditions between `dokkaJavadocCollector` and `dokkaJavadocJar` tasks
+tasks.named("dokkaJavadocCollector").configure {
+ subprojects.flatMap { it.tasks }
+ .filter { it.project.name != "courier-java" && it.name == "dokkaJavadocJar" }
+ .forEach { mustRunAfter(it) }
+}
+
+nexusPublishing {
+ repositories {
+ sonatype {
+ nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
+ snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
+
+ username.set(System.getenv("SONATYPE_USERNAME"))
+ password.set(System.getenv("SONATYPE_PASSWORD"))
+ }
+ }
+}
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
new file mode 100644
index 00000000..0b141353
--- /dev/null
+++ b/buildSrc/build.gradle.kts
@@ -0,0 +1,12 @@
+plugins {
+ `kotlin-dsl`
+ kotlin("jvm") version "1.9.20"
+}
+
+repositories {
+ gradlePluginPortal()
+}
+
+dependencies {
+ implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20")
+}
diff --git a/buildSrc/src/main/kotlin/courier.java.gradle.kts b/buildSrc/src/main/kotlin/courier.java.gradle.kts
new file mode 100644
index 00000000..81d5d32b
--- /dev/null
+++ b/buildSrc/src/main/kotlin/courier.java.gradle.kts
@@ -0,0 +1,136 @@
+import org.gradle.api.tasks.testing.logging.TestExceptionFormat
+
+plugins {
+ `java-library`
+}
+
+repositories {
+ mavenCentral()
+}
+
+configure {
+ withJavadocJar()
+ withSourcesJar()
+}
+
+java {
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(21))
+ }
+
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+}
+
+tasks.withType().configureEach {
+ options.compilerArgs.add("-Werror")
+ options.release.set(8)
+}
+
+tasks.named("javadocJar") {
+ setZip64(true)
+}
+
+tasks.named("jar") {
+ manifest {
+ attributes(mapOf(
+ "Implementation-Title" to project.name,
+ "Implementation-Version" to project.version
+ ))
+ }
+}
+
+tasks.withType().configureEach {
+ useJUnitPlatform()
+
+ // Run tests in parallel to some degree.
+ maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1)
+ forkEvery = 100
+
+ testLogging {
+ exceptionFormat = TestExceptionFormat.FULL
+ }
+}
+
+val palantir by configurations.creating
+dependencies {
+ palantir("com.palantir.javaformat:palantir-java-format:2.73.0")
+}
+
+fun registerPalantir(
+ name: String,
+ description: String,
+) {
+ val javaName = "${name}Java"
+ tasks.register(javaName) {
+ group = "Verification"
+ this.description = description
+
+ classpath = palantir
+ mainClass = "com.palantir.javaformat.java.Main"
+
+ // Avoid an `IllegalAccessError` on Java 9+.
+ jvmArgs(
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
+ )
+
+ // Use paths relative to the current module.
+ val argumentFile =
+ project.layout.buildDirectory.file("palantir-$name-args.txt").get().asFile
+ val lastRunTimeFile =
+ project.layout.buildDirectory.file("palantir-$name-last-run.txt").get().asFile
+
+ // Read the time when this task was last executed for this module (if ever).
+ val lastRunTime = lastRunTimeFile.takeIf { it.exists() }?.readText()?.toLongOrNull() ?: 0L
+
+ // Use a `fileTree` relative to the module's source directory.
+ val javaFiles = project.fileTree("src") { include("**/*.java") }
+
+ // Determine if any files need to be formatted or linted and continue only if there is at least
+ // one file.
+ onlyIf { javaFiles.any { it.lastModified() > lastRunTime } }
+
+ inputs.files(javaFiles)
+
+ doFirst {
+ // Create the argument file and set the preferred formatting style.
+ argumentFile.parentFile.mkdirs()
+ argumentFile.writeText("--palantir\n")
+
+ if (name == "lint") {
+ // For lint, do a dry run, so no files are modified. Set the exit code to 1 (instead of
+ // the default 0) if any files need to be formatted, indicating that linting has failed.
+ argumentFile.appendText("--dry-run\n")
+ argumentFile.appendText("--set-exit-if-changed\n")
+ } else {
+ // `--dry-run` and `--replace` (for in-place formatting) are mutually exclusive.
+ argumentFile.appendText("--replace\n")
+ }
+
+ // Write the modified files to the argument file.
+ javaFiles.filter { it.lastModified() > lastRunTime }
+ .forEach { argumentFile.appendText("${it.absolutePath}\n") }
+ }
+
+ doLast {
+ // Record the last execution time for later up-to-date checking.
+ lastRunTimeFile.writeText(System.currentTimeMillis().toString())
+ }
+
+ // Pass the argument file using the @ symbol
+ args = listOf("@${argumentFile.absolutePath}")
+
+ outputs.upToDateWhen { javaFiles.none { it.lastModified() > lastRunTime } }
+ }
+
+ tasks.named(name) {
+ dependsOn(tasks.named(javaName))
+ }
+}
+
+registerPalantir(name = "format", description = "Formats all Java source files.")
+registerPalantir(name = "lint", description = "Verifies all Java source files are formatted.")
diff --git a/buildSrc/src/main/kotlin/courier.kotlin.gradle.kts b/buildSrc/src/main/kotlin/courier.kotlin.gradle.kts
new file mode 100644
index 00000000..365ccefa
--- /dev/null
+++ b/buildSrc/src/main/kotlin/courier.kotlin.gradle.kts
@@ -0,0 +1,106 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
+
+plugins {
+ id("courier.java")
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+}
+
+kotlin {
+ jvmToolchain {
+ languageVersion.set(JavaLanguageVersion.of(21))
+ }
+
+ compilerOptions {
+ freeCompilerArgs = listOf(
+ "-Xjvm-default=all",
+ "-Xjdk-release=1.8",
+ // Suppress deprecation warnings because we may still reference and test deprecated members.
+ // TODO: Replace with `-Xsuppress-warning=DEPRECATION` once we use Kotlin compiler 2.1.0+.
+ "-nowarn",
+ )
+ jvmTarget.set(JvmTarget.JVM_1_8)
+ languageVersion.set(KotlinVersion.KOTLIN_1_8)
+ apiVersion.set(KotlinVersion.KOTLIN_1_8)
+ coreLibrariesVersion = "1.8.0"
+ }
+}
+
+tasks.withType().configureEach {
+ systemProperty("junit.jupiter.execution.parallel.enabled", true)
+ systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent")
+}
+
+val ktfmt by configurations.creating
+dependencies {
+ ktfmt("com.facebook:ktfmt:0.56")
+}
+
+fun registerKtfmt(
+ name: String,
+ description: String,
+) {
+ val kotlinName = "${name}Kotlin"
+ tasks.register(kotlinName) {
+ group = "Verification"
+ this.description = description
+
+ classpath = ktfmt
+ mainClass = "com.facebook.ktfmt.cli.Main"
+
+ // Use paths relative to the current module.
+ val argumentFile = project.layout.buildDirectory.file("ktfmt-$name-args.txt").get().asFile
+ val lastRunTimeFile =
+ project.layout.buildDirectory.file("ktfmt-$name-last-run.txt").get().asFile
+
+ // Read the time when this task was last executed for this module (if ever).
+ val lastRunTime = lastRunTimeFile.takeIf { it.exists() }?.readText()?.toLongOrNull() ?: 0L
+
+ // Use a `fileTree` relative to the module's source directory.
+ val kotlinFiles = project.fileTree("src") { include("**/*.kt") }
+
+ // Determine if any files need to be formatted or linted and continue only if there is at least
+ // one file (otherwise Ktfmt will fail).
+ onlyIf { kotlinFiles.any { it.lastModified() > lastRunTime } }
+
+ inputs.files(kotlinFiles)
+
+ doFirst {
+ // Create the argument file and set the preferred formatting style.
+ argumentFile.parentFile.mkdirs()
+ argumentFile.writeText("--kotlinlang-style\n")
+
+ if (name == "lint") {
+ // For lint, do a dry run, so no files are modified. Set the exit code to 1 (instead of
+ // the default 0) if any files need to be formatted, indicating that linting has failed.
+ argumentFile.appendText("--dry-run\n")
+ argumentFile.appendText("--set-exit-if-changed\n")
+ }
+
+ // Write the modified files to the argument file.
+ kotlinFiles.filter { it.lastModified() > lastRunTime }
+ .forEach { argumentFile.appendText("${it.absolutePath}\n") }
+ }
+
+ doLast {
+ // Record the last execution time for later up-to-date checking.
+ lastRunTimeFile.writeText(System.currentTimeMillis().toString())
+ }
+
+ // Pass the argument file using the @ symbol
+ args = listOf("@${argumentFile.absolutePath}")
+
+ outputs.upToDateWhen { kotlinFiles.none { it.lastModified() > lastRunTime } }
+ }
+
+ tasks.named(name) {
+ dependsOn(tasks.named(kotlinName))
+ }
+}
+
+registerKtfmt(name = "format", description = "Formats all Kotlin source files.")
+registerKtfmt(name = "lint", description = "Verifies all Kotlin source files are formatted.")
diff --git a/buildSrc/src/main/kotlin/courier.publish.gradle.kts b/buildSrc/src/main/kotlin/courier.publish.gradle.kts
new file mode 100644
index 00000000..a3deea52
--- /dev/null
+++ b/buildSrc/src/main/kotlin/courier.publish.gradle.kts
@@ -0,0 +1,60 @@
+plugins {
+ `maven-publish`
+ signing
+}
+
+configure {
+ publications {
+ register("maven") {
+ from(components["java"])
+
+ pom {
+ name.set("Courier")
+ description.set("An SDK library for courier")
+ url.set("https://www.github.com/stainless-sdks/courier-java")
+
+ licenses {
+ license {
+ name.set("Apache-2.0")
+ }
+ }
+
+ developers {
+ developer {
+ name.set("Courier")
+ }
+ }
+
+ scm {
+ connection.set("scm:git:git://github.com/stainless-sdks/courier-java.git")
+ developerConnection.set("scm:git:git://github.com/stainless-sdks/courier-java.git")
+ url.set("https://github.com/stainless-sdks/courier-java")
+ }
+
+ versionMapping {
+ allVariants {
+ fromResolutionResult()
+ }
+ }
+ }
+ }
+ }
+}
+
+signing {
+ val signingKeyId = System.getenv("GPG_SIGNING_KEY_ID")?.ifBlank { null }
+ val signingKey = System.getenv("GPG_SIGNING_KEY")?.ifBlank { null }
+ val signingPassword = System.getenv("GPG_SIGNING_PASSWORD")?.ifBlank { null }
+ if (signingKey != null && signingPassword != null) {
+ useInMemoryPgpKeys(
+ signingKeyId,
+ signingKey,
+ signingPassword,
+ )
+ sign(publishing.publications["maven"])
+ }
+}
+
+tasks.named("publish") {
+ dependsOn(":closeAndReleaseSonatypeStagingRepository")
+}
diff --git a/courier-java-client-okhttp/build.gradle.kts b/courier-java-client-okhttp/build.gradle.kts
new file mode 100644
index 00000000..4b62416c
--- /dev/null
+++ b/courier-java-client-okhttp/build.gradle.kts
@@ -0,0 +1,14 @@
+plugins {
+ id("courier.kotlin")
+ id("courier.publish")
+}
+
+dependencies {
+ api(project(":courier-java-core"))
+
+ implementation("com.squareup.okhttp3:okhttp:4.12.0")
+ implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
+
+ testImplementation(kotlin("test"))
+ testImplementation("org.assertj:assertj-core:3.25.3")
+}
diff --git a/courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClient.kt b/courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClient.kt
new file mode 100644
index 00000000..4ff91a1b
--- /dev/null
+++ b/courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClient.kt
@@ -0,0 +1,307 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.api.client.okhttp
+
+import com.courier.api.client.CourierClient
+import com.courier.api.client.CourierClientImpl
+import com.courier.api.core.ClientOptions
+import com.courier.api.core.Sleeper
+import com.courier.api.core.Timeout
+import com.courier.api.core.http.Headers
+import com.courier.api.core.http.HttpClient
+import com.courier.api.core.http.QueryParams
+import com.courier.api.core.jsonMapper
+import com.fasterxml.jackson.databind.json.JsonMapper
+import java.net.Proxy
+import java.time.Clock
+import java.time.Duration
+import java.util.Optional
+import javax.net.ssl.HostnameVerifier
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
+import kotlin.jvm.optionals.getOrNull
+
+/**
+ * A class that allows building an instance of [CourierClient] with [OkHttpClient] as the underlying
+ * [HttpClient].
+ */
+class CourierOkHttpClient private constructor() {
+
+ companion object {
+
+ /** Returns a mutable builder for constructing an instance of [CourierClient]. */
+ @JvmStatic fun builder() = Builder()
+
+ /**
+ * Returns a client configured using system properties and environment variables.
+ *
+ * @see ClientOptions.Builder.fromEnv
+ */
+ @JvmStatic fun fromEnv(): CourierClient = builder().fromEnv().build()
+ }
+
+ /** A builder for [CourierOkHttpClient]. */
+ class Builder internal constructor() {
+
+ private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
+ private var proxy: Proxy? = null
+ private var sslSocketFactory: SSLSocketFactory? = null
+ private var trustManager: X509TrustManager? = null
+ private var hostnameVerifier: HostnameVerifier? = null
+
+ fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
+
+ /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
+ fun proxy(proxy: Optional) = proxy(proxy.getOrNull())
+
+ /**
+ * The socket factory used to secure HTTPS connections.
+ *
+ * If this is set, then [trustManager] must also be set.
+ *
+ * If unset, then the system default is used. Most applications should not call this method,
+ * and instead use the system default. The default include special optimizations that can be
+ * lost if the implementation is modified.
+ */
+ fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply {
+ this.sslSocketFactory = sslSocketFactory
+ }
+
+ /** Alias for calling [Builder.sslSocketFactory] with `sslSocketFactory.orElse(null)`. */
+ fun sslSocketFactory(sslSocketFactory: Optional) =
+ sslSocketFactory(sslSocketFactory.getOrNull())
+
+ /**
+ * The trust manager used to secure HTTPS connections.
+ *
+ * If this is set, then [sslSocketFactory] must also be set.
+ *
+ * If unset, then the system default is used. Most applications should not call this method,
+ * and instead use the system default. The default include special optimizations that can be
+ * lost if the implementation is modified.
+ */
+ fun trustManager(trustManager: X509TrustManager?) = apply {
+ this.trustManager = trustManager
+ }
+
+ /** Alias for calling [Builder.trustManager] with `trustManager.orElse(null)`. */
+ fun trustManager(trustManager: Optional) =
+ trustManager(trustManager.getOrNull())
+
+ /**
+ * The verifier used to confirm that response certificates apply to requested hostnames for
+ * HTTPS connections.
+ *
+ * If unset, then a default hostname verifier is used.
+ */
+ fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply {
+ this.hostnameVerifier = hostnameVerifier
+ }
+
+ /** Alias for calling [Builder.hostnameVerifier] with `hostnameVerifier.orElse(null)`. */
+ fun hostnameVerifier(hostnameVerifier: Optional) =
+ hostnameVerifier(hostnameVerifier.getOrNull())
+
+ /**
+ * Whether to throw an exception if any of the Jackson versions detected at runtime are
+ * incompatible with the SDK's minimum supported Jackson version (2.13.4).
+ *
+ * Defaults to true. Use extreme caution when disabling this option. There is no guarantee
+ * that the SDK will work correctly when using an incompatible Jackson version.
+ */
+ fun checkJacksonVersionCompatibility(checkJacksonVersionCompatibility: Boolean) = apply {
+ clientOptions.checkJacksonVersionCompatibility(checkJacksonVersionCompatibility)
+ }
+
+ /**
+ * The Jackson JSON mapper to use for serializing and deserializing JSON.
+ *
+ * Defaults to [com.courier.api.core.jsonMapper]. The default is usually sufficient and
+ * rarely needs to be overridden.
+ */
+ fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) }
+
+ /**
+ * The interface to use for delaying execution, like during retries.
+ *
+ * This is primarily useful for using fake delays in tests.
+ *
+ * Defaults to real execution delays.
+ *
+ * This class takes ownership of the sleeper and closes it when closed.
+ */
+ fun sleeper(sleeper: Sleeper) = apply { clientOptions.sleeper(sleeper) }
+
+ /**
+ * The clock to use for operations that require timing, like retries.
+ *
+ * This is primarily useful for using a fake clock in tests.
+ *
+ * Defaults to [Clock.systemUTC].
+ */
+ fun clock(clock: Clock) = apply { clientOptions.clock(clock) }
+
+ /**
+ * The base URL to use for every request.
+ *
+ * Defaults to the production environment: `https://api.courier.com`.
+ */
+ fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) }
+
+ /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */
+ fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull())
+
+ /**
+ * Whether to call `validate` on every response before returning it.
+ *
+ * Defaults to false, which means the shape of the response will not be validated upfront.
+ * Instead, validation will only occur for the parts of the response that are accessed.
+ */
+ fun responseValidation(responseValidation: Boolean) = apply {
+ clientOptions.responseValidation(responseValidation)
+ }
+
+ /**
+ * Sets the maximum time allowed for various parts of an HTTP call's lifecycle, excluding
+ * retries.
+ *
+ * Defaults to [Timeout.default].
+ */
+ fun timeout(timeout: Timeout) = apply { clientOptions.timeout(timeout) }
+
+ /**
+ * Sets the maximum time allowed for a complete HTTP call, not including retries.
+ *
+ * See [Timeout.request] for more details.
+ *
+ * For fine-grained control, pass a [Timeout] object.
+ */
+ fun timeout(timeout: Duration) = apply { clientOptions.timeout(timeout) }
+
+ /**
+ * The maximum number of times to retry failed requests, with a short exponential backoff
+ * between requests.
+ *
+ * Only the following error types are retried:
+ * - Connection errors (for example, due to a network connectivity problem)
+ * - 408 Request Timeout
+ * - 409 Conflict
+ * - 429 Rate Limit
+ * - 5xx Internal
+ *
+ * The API may also explicitly instruct the SDK to retry or not retry a request.
+ *
+ * Defaults to 2.
+ */
+ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) }
+
+ fun apiKey(apiKey: String) = apply { clientOptions.apiKey(apiKey) }
+
+ fun headers(headers: Headers) = apply { clientOptions.headers(headers) }
+
+ fun headers(headers: Map>) = apply {
+ clientOptions.headers(headers)
+ }
+
+ fun putHeader(name: String, value: String) = apply { clientOptions.putHeader(name, value) }
+
+ fun putHeaders(name: String, values: Iterable) = apply {
+ clientOptions.putHeaders(name, values)
+ }
+
+ fun putAllHeaders(headers: Headers) = apply { clientOptions.putAllHeaders(headers) }
+
+ fun putAllHeaders(headers: Map>) = apply {
+ clientOptions.putAllHeaders(headers)
+ }
+
+ fun replaceHeaders(name: String, value: String) = apply {
+ clientOptions.replaceHeaders(name, value)
+ }
+
+ fun replaceHeaders(name: String, values: Iterable) = apply {
+ clientOptions.replaceHeaders(name, values)
+ }
+
+ fun replaceAllHeaders(headers: Headers) = apply { clientOptions.replaceAllHeaders(headers) }
+
+ fun replaceAllHeaders(headers: Map>) = apply {
+ clientOptions.replaceAllHeaders(headers)
+ }
+
+ fun removeHeaders(name: String) = apply { clientOptions.removeHeaders(name) }
+
+ fun removeAllHeaders(names: Set) = apply { clientOptions.removeAllHeaders(names) }
+
+ fun queryParams(queryParams: QueryParams) = apply { clientOptions.queryParams(queryParams) }
+
+ fun queryParams(queryParams: Map>) = apply {
+ clientOptions.queryParams(queryParams)
+ }
+
+ fun putQueryParam(key: String, value: String) = apply {
+ clientOptions.putQueryParam(key, value)
+ }
+
+ fun putQueryParams(key: String, values: Iterable) = apply {
+ clientOptions.putQueryParams(key, values)
+ }
+
+ fun putAllQueryParams(queryParams: QueryParams) = apply {
+ clientOptions.putAllQueryParams(queryParams)
+ }
+
+ fun putAllQueryParams(queryParams: Map>) = apply {
+ clientOptions.putAllQueryParams(queryParams)
+ }
+
+ fun replaceQueryParams(key: String, value: String) = apply {
+ clientOptions.replaceQueryParams(key, value)
+ }
+
+ fun replaceQueryParams(key: String, values: Iterable) = apply {
+ clientOptions.replaceQueryParams(key, values)
+ }
+
+ fun replaceAllQueryParams(queryParams: QueryParams) = apply {
+ clientOptions.replaceAllQueryParams(queryParams)
+ }
+
+ fun replaceAllQueryParams(queryParams: Map>) = apply {
+ clientOptions.replaceAllQueryParams(queryParams)
+ }
+
+ fun removeQueryParams(key: String) = apply { clientOptions.removeQueryParams(key) }
+
+ fun removeAllQueryParams(keys: Set) = apply {
+ clientOptions.removeAllQueryParams(keys)
+ }
+
+ /**
+ * Updates configuration using system properties and environment variables.
+ *
+ * @see ClientOptions.Builder.fromEnv
+ */
+ fun fromEnv() = apply { clientOptions.fromEnv() }
+
+ /**
+ * Returns an immutable instance of [CourierClient].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ */
+ fun build(): CourierClient =
+ CourierClientImpl(
+ clientOptions
+ .httpClient(
+ OkHttpClient.builder()
+ .timeout(clientOptions.timeout())
+ .proxy(proxy)
+ .sslSocketFactory(sslSocketFactory)
+ .trustManager(trustManager)
+ .hostnameVerifier(hostnameVerifier)
+ .build()
+ )
+ .build()
+ )
+ }
+}
diff --git a/courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClientAsync.kt b/courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClientAsync.kt
new file mode 100644
index 00000000..9360f485
--- /dev/null
+++ b/courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/CourierOkHttpClientAsync.kt
@@ -0,0 +1,307 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.api.client.okhttp
+
+import com.courier.api.client.CourierClientAsync
+import com.courier.api.client.CourierClientAsyncImpl
+import com.courier.api.core.ClientOptions
+import com.courier.api.core.Sleeper
+import com.courier.api.core.Timeout
+import com.courier.api.core.http.Headers
+import com.courier.api.core.http.HttpClient
+import com.courier.api.core.http.QueryParams
+import com.courier.api.core.jsonMapper
+import com.fasterxml.jackson.databind.json.JsonMapper
+import java.net.Proxy
+import java.time.Clock
+import java.time.Duration
+import java.util.Optional
+import javax.net.ssl.HostnameVerifier
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
+import kotlin.jvm.optionals.getOrNull
+
+/**
+ * A class that allows building an instance of [CourierClientAsync] with [OkHttpClient] as the
+ * underlying [HttpClient].
+ */
+class CourierOkHttpClientAsync private constructor() {
+
+ companion object {
+
+ /** Returns a mutable builder for constructing an instance of [CourierClientAsync]. */
+ @JvmStatic fun builder() = Builder()
+
+ /**
+ * Returns a client configured using system properties and environment variables.
+ *
+ * @see ClientOptions.Builder.fromEnv
+ */
+ @JvmStatic fun fromEnv(): CourierClientAsync = builder().fromEnv().build()
+ }
+
+ /** A builder for [CourierOkHttpClientAsync]. */
+ class Builder internal constructor() {
+
+ private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
+ private var proxy: Proxy? = null
+ private var sslSocketFactory: SSLSocketFactory? = null
+ private var trustManager: X509TrustManager? = null
+ private var hostnameVerifier: HostnameVerifier? = null
+
+ fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
+
+ /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
+ fun proxy(proxy: Optional) = proxy(proxy.getOrNull())
+
+ /**
+ * The socket factory used to secure HTTPS connections.
+ *
+ * If this is set, then [trustManager] must also be set.
+ *
+ * If unset, then the system default is used. Most applications should not call this method,
+ * and instead use the system default. The default include special optimizations that can be
+ * lost if the implementation is modified.
+ */
+ fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply {
+ this.sslSocketFactory = sslSocketFactory
+ }
+
+ /** Alias for calling [Builder.sslSocketFactory] with `sslSocketFactory.orElse(null)`. */
+ fun sslSocketFactory(sslSocketFactory: Optional) =
+ sslSocketFactory(sslSocketFactory.getOrNull())
+
+ /**
+ * The trust manager used to secure HTTPS connections.
+ *
+ * If this is set, then [sslSocketFactory] must also be set.
+ *
+ * If unset, then the system default is used. Most applications should not call this method,
+ * and instead use the system default. The default include special optimizations that can be
+ * lost if the implementation is modified.
+ */
+ fun trustManager(trustManager: X509TrustManager?) = apply {
+ this.trustManager = trustManager
+ }
+
+ /** Alias for calling [Builder.trustManager] with `trustManager.orElse(null)`. */
+ fun trustManager(trustManager: Optional) =
+ trustManager(trustManager.getOrNull())
+
+ /**
+ * The verifier used to confirm that response certificates apply to requested hostnames for
+ * HTTPS connections.
+ *
+ * If unset, then a default hostname verifier is used.
+ */
+ fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply {
+ this.hostnameVerifier = hostnameVerifier
+ }
+
+ /** Alias for calling [Builder.hostnameVerifier] with `hostnameVerifier.orElse(null)`. */
+ fun hostnameVerifier(hostnameVerifier: Optional) =
+ hostnameVerifier(hostnameVerifier.getOrNull())
+
+ /**
+ * Whether to throw an exception if any of the Jackson versions detected at runtime are
+ * incompatible with the SDK's minimum supported Jackson version (2.13.4).
+ *
+ * Defaults to true. Use extreme caution when disabling this option. There is no guarantee
+ * that the SDK will work correctly when using an incompatible Jackson version.
+ */
+ fun checkJacksonVersionCompatibility(checkJacksonVersionCompatibility: Boolean) = apply {
+ clientOptions.checkJacksonVersionCompatibility(checkJacksonVersionCompatibility)
+ }
+
+ /**
+ * The Jackson JSON mapper to use for serializing and deserializing JSON.
+ *
+ * Defaults to [com.courier.api.core.jsonMapper]. The default is usually sufficient and
+ * rarely needs to be overridden.
+ */
+ fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) }
+
+ /**
+ * The interface to use for delaying execution, like during retries.
+ *
+ * This is primarily useful for using fake delays in tests.
+ *
+ * Defaults to real execution delays.
+ *
+ * This class takes ownership of the sleeper and closes it when closed.
+ */
+ fun sleeper(sleeper: Sleeper) = apply { clientOptions.sleeper(sleeper) }
+
+ /**
+ * The clock to use for operations that require timing, like retries.
+ *
+ * This is primarily useful for using a fake clock in tests.
+ *
+ * Defaults to [Clock.systemUTC].
+ */
+ fun clock(clock: Clock) = apply { clientOptions.clock(clock) }
+
+ /**
+ * The base URL to use for every request.
+ *
+ * Defaults to the production environment: `https://api.courier.com`.
+ */
+ fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) }
+
+ /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */
+ fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull())
+
+ /**
+ * Whether to call `validate` on every response before returning it.
+ *
+ * Defaults to false, which means the shape of the response will not be validated upfront.
+ * Instead, validation will only occur for the parts of the response that are accessed.
+ */
+ fun responseValidation(responseValidation: Boolean) = apply {
+ clientOptions.responseValidation(responseValidation)
+ }
+
+ /**
+ * Sets the maximum time allowed for various parts of an HTTP call's lifecycle, excluding
+ * retries.
+ *
+ * Defaults to [Timeout.default].
+ */
+ fun timeout(timeout: Timeout) = apply { clientOptions.timeout(timeout) }
+
+ /**
+ * Sets the maximum time allowed for a complete HTTP call, not including retries.
+ *
+ * See [Timeout.request] for more details.
+ *
+ * For fine-grained control, pass a [Timeout] object.
+ */
+ fun timeout(timeout: Duration) = apply { clientOptions.timeout(timeout) }
+
+ /**
+ * The maximum number of times to retry failed requests, with a short exponential backoff
+ * between requests.
+ *
+ * Only the following error types are retried:
+ * - Connection errors (for example, due to a network connectivity problem)
+ * - 408 Request Timeout
+ * - 409 Conflict
+ * - 429 Rate Limit
+ * - 5xx Internal
+ *
+ * The API may also explicitly instruct the SDK to retry or not retry a request.
+ *
+ * Defaults to 2.
+ */
+ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) }
+
+ fun apiKey(apiKey: String) = apply { clientOptions.apiKey(apiKey) }
+
+ fun headers(headers: Headers) = apply { clientOptions.headers(headers) }
+
+ fun headers(headers: Map>) = apply {
+ clientOptions.headers(headers)
+ }
+
+ fun putHeader(name: String, value: String) = apply { clientOptions.putHeader(name, value) }
+
+ fun putHeaders(name: String, values: Iterable) = apply {
+ clientOptions.putHeaders(name, values)
+ }
+
+ fun putAllHeaders(headers: Headers) = apply { clientOptions.putAllHeaders(headers) }
+
+ fun putAllHeaders(headers: Map>) = apply {
+ clientOptions.putAllHeaders(headers)
+ }
+
+ fun replaceHeaders(name: String, value: String) = apply {
+ clientOptions.replaceHeaders(name, value)
+ }
+
+ fun replaceHeaders(name: String, values: Iterable) = apply {
+ clientOptions.replaceHeaders(name, values)
+ }
+
+ fun replaceAllHeaders(headers: Headers) = apply { clientOptions.replaceAllHeaders(headers) }
+
+ fun replaceAllHeaders(headers: Map>) = apply {
+ clientOptions.replaceAllHeaders(headers)
+ }
+
+ fun removeHeaders(name: String) = apply { clientOptions.removeHeaders(name) }
+
+ fun removeAllHeaders(names: Set) = apply { clientOptions.removeAllHeaders(names) }
+
+ fun queryParams(queryParams: QueryParams) = apply { clientOptions.queryParams(queryParams) }
+
+ fun queryParams(queryParams: Map>) = apply {
+ clientOptions.queryParams(queryParams)
+ }
+
+ fun putQueryParam(key: String, value: String) = apply {
+ clientOptions.putQueryParam(key, value)
+ }
+
+ fun putQueryParams(key: String, values: Iterable) = apply {
+ clientOptions.putQueryParams(key, values)
+ }
+
+ fun putAllQueryParams(queryParams: QueryParams) = apply {
+ clientOptions.putAllQueryParams(queryParams)
+ }
+
+ fun putAllQueryParams(queryParams: Map>) = apply {
+ clientOptions.putAllQueryParams(queryParams)
+ }
+
+ fun replaceQueryParams(key: String, value: String) = apply {
+ clientOptions.replaceQueryParams(key, value)
+ }
+
+ fun replaceQueryParams(key: String, values: Iterable) = apply {
+ clientOptions.replaceQueryParams(key, values)
+ }
+
+ fun replaceAllQueryParams(queryParams: QueryParams) = apply {
+ clientOptions.replaceAllQueryParams(queryParams)
+ }
+
+ fun replaceAllQueryParams(queryParams: Map>) = apply {
+ clientOptions.replaceAllQueryParams(queryParams)
+ }
+
+ fun removeQueryParams(key: String) = apply { clientOptions.removeQueryParams(key) }
+
+ fun removeAllQueryParams(keys: Set) = apply {
+ clientOptions.removeAllQueryParams(keys)
+ }
+
+ /**
+ * Updates configuration using system properties and environment variables.
+ *
+ * @see ClientOptions.Builder.fromEnv
+ */
+ fun fromEnv() = apply { clientOptions.fromEnv() }
+
+ /**
+ * Returns an immutable instance of [CourierClientAsync].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ */
+ fun build(): CourierClientAsync =
+ CourierClientAsyncImpl(
+ clientOptions
+ .httpClient(
+ OkHttpClient.builder()
+ .timeout(clientOptions.timeout())
+ .proxy(proxy)
+ .sslSocketFactory(sslSocketFactory)
+ .trustManager(trustManager)
+ .hostnameVerifier(hostnameVerifier)
+ .build()
+ )
+ .build()
+ )
+ }
+}
diff --git a/courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/OkHttpClient.kt b/courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/OkHttpClient.kt
new file mode 100644
index 00000000..33ff3abe
--- /dev/null
+++ b/courier-java-client-okhttp/src/main/kotlin/com/courier/api/client/okhttp/OkHttpClient.kt
@@ -0,0 +1,246 @@
+package com.courier.api.client.okhttp
+
+import com.courier.api.core.RequestOptions
+import com.courier.api.core.Timeout
+import com.courier.api.core.http.Headers
+import com.courier.api.core.http.HttpClient
+import com.courier.api.core.http.HttpMethod
+import com.courier.api.core.http.HttpRequest
+import com.courier.api.core.http.HttpRequestBody
+import com.courier.api.core.http.HttpResponse
+import com.courier.api.errors.CourierIoException
+import java.io.IOException
+import java.io.InputStream
+import java.net.Proxy
+import java.time.Duration
+import java.util.concurrent.CompletableFuture
+import javax.net.ssl.HostnameVerifier
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
+import okhttp3.Call
+import okhttp3.Callback
+import okhttp3.HttpUrl.Companion.toHttpUrl
+import okhttp3.MediaType
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.Request
+import okhttp3.RequestBody
+import okhttp3.RequestBody.Companion.toRequestBody
+import okhttp3.Response
+import okhttp3.logging.HttpLoggingInterceptor
+import okio.BufferedSink
+
+class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpClient) :
+ HttpClient {
+
+ override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse {
+ val call = newCall(request, requestOptions)
+
+ return try {
+ call.execute().toResponse()
+ } catch (e: IOException) {
+ throw CourierIoException("Request failed", e)
+ } finally {
+ request.body?.close()
+ }
+ }
+
+ override fun executeAsync(
+ request: HttpRequest,
+ requestOptions: RequestOptions,
+ ): CompletableFuture {
+ val future = CompletableFuture()
+
+ request.body?.run { future.whenComplete { _, _ -> close() } }
+
+ newCall(request, requestOptions)
+ .enqueue(
+ object : Callback {
+ override fun onResponse(call: Call, response: Response) {
+ future.complete(response.toResponse())
+ }
+
+ override fun onFailure(call: Call, e: IOException) {
+ future.completeExceptionally(CourierIoException("Request failed", e))
+ }
+ }
+ )
+
+ return future
+ }
+
+ override fun close() {
+ okHttpClient.dispatcher.executorService.shutdown()
+ okHttpClient.connectionPool.evictAll()
+ okHttpClient.cache?.close()
+ }
+
+ private fun newCall(request: HttpRequest, requestOptions: RequestOptions): Call {
+ val clientBuilder = okHttpClient.newBuilder()
+
+ val logLevel =
+ when (System.getenv("COURIER_LOG")?.lowercase()) {
+ "info" -> HttpLoggingInterceptor.Level.BASIC
+ "debug" -> HttpLoggingInterceptor.Level.BODY
+ else -> null
+ }
+ if (logLevel != null) {
+ clientBuilder.addNetworkInterceptor(
+ HttpLoggingInterceptor().setLevel(logLevel).apply { redactHeader("Authorization") }
+ )
+ }
+
+ requestOptions.timeout?.let {
+ clientBuilder
+ .connectTimeout(it.connect())
+ .readTimeout(it.read())
+ .writeTimeout(it.write())
+ .callTimeout(it.request())
+ }
+
+ val client = clientBuilder.build()
+ return client.newCall(request.toRequest(client))
+ }
+
+ private fun HttpRequest.toRequest(client: okhttp3.OkHttpClient): Request {
+ var body: RequestBody? = body?.toRequestBody()
+ if (body == null && requiresBody(method)) {
+ body = "".toRequestBody()
+ }
+
+ val builder = Request.Builder().url(toUrl()).method(method.name, body)
+ headers.names().forEach { name ->
+ headers.values(name).forEach { builder.header(name, it) }
+ }
+
+ if (
+ !headers.names().contains("X-Stainless-Read-Timeout") && client.readTimeoutMillis != 0
+ ) {
+ builder.header(
+ "X-Stainless-Read-Timeout",
+ Duration.ofMillis(client.readTimeoutMillis.toLong()).seconds.toString(),
+ )
+ }
+ if (!headers.names().contains("X-Stainless-Timeout") && client.callTimeoutMillis != 0) {
+ builder.header(
+ "X-Stainless-Timeout",
+ Duration.ofMillis(client.callTimeoutMillis.toLong()).seconds.toString(),
+ )
+ }
+
+ return builder.build()
+ }
+
+ /** `OkHttpClient` always requires a request body for some methods. */
+ private fun requiresBody(method: HttpMethod): Boolean =
+ when (method) {
+ HttpMethod.POST,
+ HttpMethod.PUT,
+ HttpMethod.PATCH -> true
+ else -> false
+ }
+
+ private fun HttpRequest.toUrl(): String {
+ val builder = baseUrl.toHttpUrl().newBuilder()
+ pathSegments.forEach(builder::addPathSegment)
+ queryParams.keys().forEach { key ->
+ queryParams.values(key).forEach { builder.addQueryParameter(key, it) }
+ }
+
+ return builder.toString()
+ }
+
+ private fun HttpRequestBody.toRequestBody(): RequestBody {
+ val mediaType = contentType()?.toMediaType()
+ val length = contentLength()
+
+ return object : RequestBody() {
+ override fun contentType(): MediaType? = mediaType
+
+ override fun contentLength(): Long = length
+
+ override fun isOneShot(): Boolean = !repeatable()
+
+ override fun writeTo(sink: BufferedSink) = writeTo(sink.outputStream())
+ }
+ }
+
+ private fun Response.toResponse(): HttpResponse {
+ val headers = headers.toHeaders()
+
+ return object : HttpResponse {
+ override fun statusCode(): Int = code
+
+ override fun headers(): Headers = headers
+
+ override fun body(): InputStream = body!!.byteStream()
+
+ override fun close() = body!!.close()
+ }
+ }
+
+ private fun okhttp3.Headers.toHeaders(): Headers {
+ val headersBuilder = Headers.builder()
+ forEach { (name, value) -> headersBuilder.put(name, value) }
+ return headersBuilder.build()
+ }
+
+ companion object {
+ @JvmStatic fun builder() = Builder()
+ }
+
+ class Builder internal constructor() {
+
+ private var timeout: Timeout = Timeout.default()
+ private var proxy: Proxy? = null
+ private var sslSocketFactory: SSLSocketFactory? = null
+ private var trustManager: X509TrustManager? = null
+ private var hostnameVerifier: HostnameVerifier? = null
+
+ fun timeout(timeout: Timeout) = apply { this.timeout = timeout }
+
+ fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build())
+
+ fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
+
+ fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply {
+ this.sslSocketFactory = sslSocketFactory
+ }
+
+ fun trustManager(trustManager: X509TrustManager?) = apply {
+ this.trustManager = trustManager
+ }
+
+ fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply {
+ this.hostnameVerifier = hostnameVerifier
+ }
+
+ fun build(): OkHttpClient =
+ OkHttpClient(
+ okhttp3.OkHttpClient.Builder()
+ .connectTimeout(timeout.connect())
+ .readTimeout(timeout.read())
+ .writeTimeout(timeout.write())
+ .callTimeout(timeout.request())
+ .proxy(proxy)
+ .apply {
+ val sslSocketFactory = sslSocketFactory
+ val trustManager = trustManager
+ if (sslSocketFactory != null && trustManager != null) {
+ sslSocketFactory(sslSocketFactory, trustManager)
+ } else {
+ check((sslSocketFactory != null) == (trustManager != null)) {
+ "Both or none of `sslSocketFactory` and `trustManager` must be set, but only one was set"
+ }
+ }
+
+ hostnameVerifier?.let(::hostnameVerifier)
+ }
+ .build()
+ .apply {
+ // We usually make all our requests to the same host so it makes sense to
+ // raise the per-host limit to the overall limit.
+ dispatcher.maxRequestsPerHost = dispatcher.maxRequests
+ }
+ )
+ }
+}
diff --git a/courier-java-core/build.gradle.kts b/courier-java-core/build.gradle.kts
new file mode 100644
index 00000000..d31e4b11
--- /dev/null
+++ b/courier-java-core/build.gradle.kts
@@ -0,0 +1,41 @@
+plugins {
+ id("courier.kotlin")
+ id("courier.publish")
+}
+
+configurations.all {
+ resolutionStrategy {
+ // Compile and test against a lower Jackson version to ensure we're compatible with it.
+ // We publish with a higher version (see below) to ensure users depend on a secure version by default.
+ force("com.fasterxml.jackson.core:jackson-core:2.13.4")
+ force("com.fasterxml.jackson.core:jackson-databind:2.13.4")
+ force("com.fasterxml.jackson.core:jackson-annotations:2.13.4")
+ force("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.4")
+ force("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4")
+ force("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4")
+ }
+}
+
+dependencies {
+ api("com.fasterxml.jackson.core:jackson-core:2.18.2")
+ api("com.fasterxml.jackson.core:jackson-databind:2.18.2")
+ api("com.google.errorprone:error_prone_annotations:2.33.0")
+
+ implementation("com.fasterxml.jackson.core:jackson-annotations:2.18.2")
+ implementation("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.18.2")
+ implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.2")
+ implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.2")
+ implementation("org.apache.httpcomponents.core5:httpcore5:5.2.4")
+ implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1")
+
+ testImplementation(kotlin("test"))
+ testImplementation(project(":courier-java-client-okhttp"))
+ testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2")
+ testImplementation("org.assertj:assertj-core:3.25.3")
+ testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3")
+ testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.3")
+ testImplementation("org.junit-pioneer:junit-pioneer:1.9.1")
+ testImplementation("org.mockito:mockito-core:5.14.2")
+ testImplementation("org.mockito:mockito-junit-jupiter:5.14.2")
+ testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0")
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClient.kt b/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClient.kt
new file mode 100644
index 00000000..180e5483
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClient.kt
@@ -0,0 +1,147 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.api.client
+
+import com.courier.api.core.ClientOptions
+import com.courier.api.services.blocking.AudienceService
+import com.courier.api.services.blocking.AuditEventService
+import com.courier.api.services.blocking.AuthService
+import com.courier.api.services.blocking.AutomationService
+import com.courier.api.services.blocking.BrandService
+import com.courier.api.services.blocking.BulkService
+import com.courier.api.services.blocking.InboundService
+import com.courier.api.services.blocking.ListService
+import com.courier.api.services.blocking.MessageService
+import com.courier.api.services.blocking.NotificationService
+import com.courier.api.services.blocking.ProfileService
+import com.courier.api.services.blocking.RequestService
+import com.courier.api.services.blocking.SendService
+import com.courier.api.services.blocking.TenantService
+import com.courier.api.services.blocking.TranslationService
+import com.courier.api.services.blocking.UserService
+import java.util.function.Consumer
+
+/**
+ * A client for interacting with the Courier REST API synchronously. You can also switch to
+ * asynchronous execution via the [async] method.
+ *
+ * This client performs best when you create a single instance and reuse it for all interactions
+ * with the REST API. This is because each client holds its own connection pool and thread pools.
+ * Reusing connections and threads reduces latency and saves memory. The client also handles rate
+ * limiting per client. This means that creating and using multiple instances at the same time will
+ * not respect rate limits.
+ *
+ * The threads and connections that are held will be released automatically if they remain idle. But
+ * if you are writing an application that needs to aggressively release unused resources, then you
+ * may call [close].
+ */
+interface CourierClient {
+
+ /**
+ * Returns a version of this client that uses asynchronous execution.
+ *
+ * The returned client shares its resources, like its connection pool and thread pools, with
+ * this client.
+ */
+ fun async(): CourierClientAsync
+
+ /**
+ * Returns a view of this service that provides access to raw HTTP responses for each method.
+ */
+ fun withRawResponse(): WithRawResponse
+
+ /**
+ * Returns a view of this service with the given option modifications applied.
+ *
+ * The original service is not modified.
+ */
+ fun withOptions(modifier: Consumer): CourierClient
+
+ fun send(): SendService
+
+ fun audiences(): AudienceService
+
+ fun auditEvents(): AuditEventService
+
+ fun auth(): AuthService
+
+ fun automations(): AutomationService
+
+ fun brands(): BrandService
+
+ fun bulk(): BulkService
+
+ fun inbound(): InboundService
+
+ fun lists(): ListService
+
+ fun messages(): MessageService
+
+ fun requests(): RequestService
+
+ fun notifications(): NotificationService
+
+ fun profiles(): ProfileService
+
+ fun tenants(): TenantService
+
+ fun translations(): TranslationService
+
+ fun users(): UserService
+
+ /**
+ * Closes this client, relinquishing any underlying resources.
+ *
+ * This is purposefully not inherited from [AutoCloseable] because the client is long-lived and
+ * usually should not be synchronously closed via try-with-resources.
+ *
+ * It's also usually not necessary to call this method at all. the default HTTP client
+ * automatically releases threads and connections if they remain idle, but if you are writing an
+ * application that needs to aggressively release unused resources, then you may call this
+ * method.
+ */
+ fun close()
+
+ /** A view of [CourierClient] that provides access to raw HTTP responses for each method. */
+ interface WithRawResponse {
+
+ /**
+ * Returns a view of this service with the given option modifications applied.
+ *
+ * The original service is not modified.
+ */
+ fun withOptions(modifier: Consumer): CourierClient.WithRawResponse
+
+ fun send(): SendService.WithRawResponse
+
+ fun audiences(): AudienceService.WithRawResponse
+
+ fun auditEvents(): AuditEventService.WithRawResponse
+
+ fun auth(): AuthService.WithRawResponse
+
+ fun automations(): AutomationService.WithRawResponse
+
+ fun brands(): BrandService.WithRawResponse
+
+ fun bulk(): BulkService.WithRawResponse
+
+ fun inbound(): InboundService.WithRawResponse
+
+ fun lists(): ListService.WithRawResponse
+
+ fun messages(): MessageService.WithRawResponse
+
+ fun requests(): RequestService.WithRawResponse
+
+ fun notifications(): NotificationService.WithRawResponse
+
+ fun profiles(): ProfileService.WithRawResponse
+
+ fun tenants(): TenantService.WithRawResponse
+
+ fun translations(): TranslationService.WithRawResponse
+
+ fun users(): UserService.WithRawResponse
+ }
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsync.kt b/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsync.kt
new file mode 100644
index 00000000..c9af54aa
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsync.kt
@@ -0,0 +1,151 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.api.client
+
+import com.courier.api.core.ClientOptions
+import com.courier.api.services.async.AudienceServiceAsync
+import com.courier.api.services.async.AuditEventServiceAsync
+import com.courier.api.services.async.AuthServiceAsync
+import com.courier.api.services.async.AutomationServiceAsync
+import com.courier.api.services.async.BrandServiceAsync
+import com.courier.api.services.async.BulkServiceAsync
+import com.courier.api.services.async.InboundServiceAsync
+import com.courier.api.services.async.ListServiceAsync
+import com.courier.api.services.async.MessageServiceAsync
+import com.courier.api.services.async.NotificationServiceAsync
+import com.courier.api.services.async.ProfileServiceAsync
+import com.courier.api.services.async.RequestServiceAsync
+import com.courier.api.services.async.SendServiceAsync
+import com.courier.api.services.async.TenantServiceAsync
+import com.courier.api.services.async.TranslationServiceAsync
+import com.courier.api.services.async.UserServiceAsync
+import java.util.function.Consumer
+
+/**
+ * A client for interacting with the Courier REST API asynchronously. You can also switch to
+ * synchronous execution via the [sync] method.
+ *
+ * This client performs best when you create a single instance and reuse it for all interactions
+ * with the REST API. This is because each client holds its own connection pool and thread pools.
+ * Reusing connections and threads reduces latency and saves memory. The client also handles rate
+ * limiting per client. This means that creating and using multiple instances at the same time will
+ * not respect rate limits.
+ *
+ * The threads and connections that are held will be released automatically if they remain idle. But
+ * if you are writing an application that needs to aggressively release unused resources, then you
+ * may call [close].
+ */
+interface CourierClientAsync {
+
+ /**
+ * Returns a version of this client that uses synchronous execution.
+ *
+ * The returned client shares its resources, like its connection pool and thread pools, with
+ * this client.
+ */
+ fun sync(): CourierClient
+
+ /**
+ * Returns a view of this service that provides access to raw HTTP responses for each method.
+ */
+ fun withRawResponse(): WithRawResponse
+
+ /**
+ * Returns a view of this service with the given option modifications applied.
+ *
+ * The original service is not modified.
+ */
+ fun withOptions(modifier: Consumer): CourierClientAsync
+
+ fun send(): SendServiceAsync
+
+ fun audiences(): AudienceServiceAsync
+
+ fun auditEvents(): AuditEventServiceAsync
+
+ fun auth(): AuthServiceAsync
+
+ fun automations(): AutomationServiceAsync
+
+ fun brands(): BrandServiceAsync
+
+ fun bulk(): BulkServiceAsync
+
+ fun inbound(): InboundServiceAsync
+
+ fun lists(): ListServiceAsync
+
+ fun messages(): MessageServiceAsync
+
+ fun requests(): RequestServiceAsync
+
+ fun notifications(): NotificationServiceAsync
+
+ fun profiles(): ProfileServiceAsync
+
+ fun tenants(): TenantServiceAsync
+
+ fun translations(): TranslationServiceAsync
+
+ fun users(): UserServiceAsync
+
+ /**
+ * Closes this client, relinquishing any underlying resources.
+ *
+ * This is purposefully not inherited from [AutoCloseable] because the client is long-lived and
+ * usually should not be synchronously closed via try-with-resources.
+ *
+ * It's also usually not necessary to call this method at all. the default HTTP client
+ * automatically releases threads and connections if they remain idle, but if you are writing an
+ * application that needs to aggressively release unused resources, then you may call this
+ * method.
+ */
+ fun close()
+
+ /**
+ * A view of [CourierClientAsync] that provides access to raw HTTP responses for each method.
+ */
+ interface WithRawResponse {
+
+ /**
+ * Returns a view of this service with the given option modifications applied.
+ *
+ * The original service is not modified.
+ */
+ fun withOptions(
+ modifier: Consumer
+ ): CourierClientAsync.WithRawResponse
+
+ fun send(): SendServiceAsync.WithRawResponse
+
+ fun audiences(): AudienceServiceAsync.WithRawResponse
+
+ fun auditEvents(): AuditEventServiceAsync.WithRawResponse
+
+ fun auth(): AuthServiceAsync.WithRawResponse
+
+ fun automations(): AutomationServiceAsync.WithRawResponse
+
+ fun brands(): BrandServiceAsync.WithRawResponse
+
+ fun bulk(): BulkServiceAsync.WithRawResponse
+
+ fun inbound(): InboundServiceAsync.WithRawResponse
+
+ fun lists(): ListServiceAsync.WithRawResponse
+
+ fun messages(): MessageServiceAsync.WithRawResponse
+
+ fun requests(): RequestServiceAsync.WithRawResponse
+
+ fun notifications(): NotificationServiceAsync.WithRawResponse
+
+ fun profiles(): ProfileServiceAsync.WithRawResponse
+
+ fun tenants(): TenantServiceAsync.WithRawResponse
+
+ fun translations(): TranslationServiceAsync.WithRawResponse
+
+ fun users(): UserServiceAsync.WithRawResponse
+ }
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsyncImpl.kt b/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsyncImpl.kt
new file mode 100644
index 00000000..01a0126c
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientAsyncImpl.kt
@@ -0,0 +1,259 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.api.client
+
+import com.courier.api.core.ClientOptions
+import com.courier.api.core.getPackageVersion
+import com.courier.api.services.async.AudienceServiceAsync
+import com.courier.api.services.async.AudienceServiceAsyncImpl
+import com.courier.api.services.async.AuditEventServiceAsync
+import com.courier.api.services.async.AuditEventServiceAsyncImpl
+import com.courier.api.services.async.AuthServiceAsync
+import com.courier.api.services.async.AuthServiceAsyncImpl
+import com.courier.api.services.async.AutomationServiceAsync
+import com.courier.api.services.async.AutomationServiceAsyncImpl
+import com.courier.api.services.async.BrandServiceAsync
+import com.courier.api.services.async.BrandServiceAsyncImpl
+import com.courier.api.services.async.BulkServiceAsync
+import com.courier.api.services.async.BulkServiceAsyncImpl
+import com.courier.api.services.async.InboundServiceAsync
+import com.courier.api.services.async.InboundServiceAsyncImpl
+import com.courier.api.services.async.ListServiceAsync
+import com.courier.api.services.async.ListServiceAsyncImpl
+import com.courier.api.services.async.MessageServiceAsync
+import com.courier.api.services.async.MessageServiceAsyncImpl
+import com.courier.api.services.async.NotificationServiceAsync
+import com.courier.api.services.async.NotificationServiceAsyncImpl
+import com.courier.api.services.async.ProfileServiceAsync
+import com.courier.api.services.async.ProfileServiceAsyncImpl
+import com.courier.api.services.async.RequestServiceAsync
+import com.courier.api.services.async.RequestServiceAsyncImpl
+import com.courier.api.services.async.SendServiceAsync
+import com.courier.api.services.async.SendServiceAsyncImpl
+import com.courier.api.services.async.TenantServiceAsync
+import com.courier.api.services.async.TenantServiceAsyncImpl
+import com.courier.api.services.async.TranslationServiceAsync
+import com.courier.api.services.async.TranslationServiceAsyncImpl
+import com.courier.api.services.async.UserServiceAsync
+import com.courier.api.services.async.UserServiceAsyncImpl
+import java.util.function.Consumer
+
+class CourierClientAsyncImpl(private val clientOptions: ClientOptions) : CourierClientAsync {
+
+ private val clientOptionsWithUserAgent =
+ if (clientOptions.headers.names().contains("User-Agent")) clientOptions
+ else
+ clientOptions
+ .toBuilder()
+ .putHeader("User-Agent", "${javaClass.simpleName}/Java ${getPackageVersion()}")
+ .build()
+
+ // Pass the original clientOptions so that this client sets its own User-Agent.
+ private val sync: CourierClient by lazy { CourierClientImpl(clientOptions) }
+
+ private val withRawResponse: CourierClientAsync.WithRawResponse by lazy {
+ WithRawResponseImpl(clientOptions)
+ }
+
+ private val send: SendServiceAsync by lazy { SendServiceAsyncImpl(clientOptionsWithUserAgent) }
+
+ private val audiences: AudienceServiceAsync by lazy {
+ AudienceServiceAsyncImpl(clientOptionsWithUserAgent)
+ }
+
+ private val auditEvents: AuditEventServiceAsync by lazy {
+ AuditEventServiceAsyncImpl(clientOptionsWithUserAgent)
+ }
+
+ private val auth: AuthServiceAsync by lazy { AuthServiceAsyncImpl(clientOptionsWithUserAgent) }
+
+ private val automations: AutomationServiceAsync by lazy {
+ AutomationServiceAsyncImpl(clientOptionsWithUserAgent)
+ }
+
+ private val brands: BrandServiceAsync by lazy {
+ BrandServiceAsyncImpl(clientOptionsWithUserAgent)
+ }
+
+ private val bulk: BulkServiceAsync by lazy { BulkServiceAsyncImpl(clientOptionsWithUserAgent) }
+
+ private val inbound: InboundServiceAsync by lazy {
+ InboundServiceAsyncImpl(clientOptionsWithUserAgent)
+ }
+
+ private val lists: ListServiceAsync by lazy { ListServiceAsyncImpl(clientOptionsWithUserAgent) }
+
+ private val messages: MessageServiceAsync by lazy {
+ MessageServiceAsyncImpl(clientOptionsWithUserAgent)
+ }
+
+ private val requests: RequestServiceAsync by lazy {
+ RequestServiceAsyncImpl(clientOptionsWithUserAgent)
+ }
+
+ private val notifications: NotificationServiceAsync by lazy {
+ NotificationServiceAsyncImpl(clientOptionsWithUserAgent)
+ }
+
+ private val profiles: ProfileServiceAsync by lazy {
+ ProfileServiceAsyncImpl(clientOptionsWithUserAgent)
+ }
+
+ private val tenants: TenantServiceAsync by lazy {
+ TenantServiceAsyncImpl(clientOptionsWithUserAgent)
+ }
+
+ private val translations: TranslationServiceAsync by lazy {
+ TranslationServiceAsyncImpl(clientOptionsWithUserAgent)
+ }
+
+ private val users: UserServiceAsync by lazy { UserServiceAsyncImpl(clientOptionsWithUserAgent) }
+
+ override fun sync(): CourierClient = sync
+
+ override fun withRawResponse(): CourierClientAsync.WithRawResponse = withRawResponse
+
+ override fun withOptions(modifier: Consumer): CourierClientAsync =
+ CourierClientAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build())
+
+ override fun send(): SendServiceAsync = send
+
+ override fun audiences(): AudienceServiceAsync = audiences
+
+ override fun auditEvents(): AuditEventServiceAsync = auditEvents
+
+ override fun auth(): AuthServiceAsync = auth
+
+ override fun automations(): AutomationServiceAsync = automations
+
+ override fun brands(): BrandServiceAsync = brands
+
+ override fun bulk(): BulkServiceAsync = bulk
+
+ override fun inbound(): InboundServiceAsync = inbound
+
+ override fun lists(): ListServiceAsync = lists
+
+ override fun messages(): MessageServiceAsync = messages
+
+ override fun requests(): RequestServiceAsync = requests
+
+ override fun notifications(): NotificationServiceAsync = notifications
+
+ override fun profiles(): ProfileServiceAsync = profiles
+
+ override fun tenants(): TenantServiceAsync = tenants
+
+ override fun translations(): TranslationServiceAsync = translations
+
+ override fun users(): UserServiceAsync = users
+
+ override fun close() = clientOptions.close()
+
+ class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) :
+ CourierClientAsync.WithRawResponse {
+
+ private val send: SendServiceAsync.WithRawResponse by lazy {
+ SendServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val audiences: AudienceServiceAsync.WithRawResponse by lazy {
+ AudienceServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val auditEvents: AuditEventServiceAsync.WithRawResponse by lazy {
+ AuditEventServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val auth: AuthServiceAsync.WithRawResponse by lazy {
+ AuthServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val automations: AutomationServiceAsync.WithRawResponse by lazy {
+ AutomationServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val brands: BrandServiceAsync.WithRawResponse by lazy {
+ BrandServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val bulk: BulkServiceAsync.WithRawResponse by lazy {
+ BulkServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val inbound: InboundServiceAsync.WithRawResponse by lazy {
+ InboundServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val lists: ListServiceAsync.WithRawResponse by lazy {
+ ListServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val messages: MessageServiceAsync.WithRawResponse by lazy {
+ MessageServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val requests: RequestServiceAsync.WithRawResponse by lazy {
+ RequestServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val notifications: NotificationServiceAsync.WithRawResponse by lazy {
+ NotificationServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val profiles: ProfileServiceAsync.WithRawResponse by lazy {
+ ProfileServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val tenants: TenantServiceAsync.WithRawResponse by lazy {
+ TenantServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val translations: TranslationServiceAsync.WithRawResponse by lazy {
+ TranslationServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val users: UserServiceAsync.WithRawResponse by lazy {
+ UserServiceAsyncImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ override fun withOptions(
+ modifier: Consumer
+ ): CourierClientAsync.WithRawResponse =
+ CourierClientAsyncImpl.WithRawResponseImpl(
+ clientOptions.toBuilder().apply(modifier::accept).build()
+ )
+
+ override fun send(): SendServiceAsync.WithRawResponse = send
+
+ override fun audiences(): AudienceServiceAsync.WithRawResponse = audiences
+
+ override fun auditEvents(): AuditEventServiceAsync.WithRawResponse = auditEvents
+
+ override fun auth(): AuthServiceAsync.WithRawResponse = auth
+
+ override fun automations(): AutomationServiceAsync.WithRawResponse = automations
+
+ override fun brands(): BrandServiceAsync.WithRawResponse = brands
+
+ override fun bulk(): BulkServiceAsync.WithRawResponse = bulk
+
+ override fun inbound(): InboundServiceAsync.WithRawResponse = inbound
+
+ override fun lists(): ListServiceAsync.WithRawResponse = lists
+
+ override fun messages(): MessageServiceAsync.WithRawResponse = messages
+
+ override fun requests(): RequestServiceAsync.WithRawResponse = requests
+
+ override fun notifications(): NotificationServiceAsync.WithRawResponse = notifications
+
+ override fun profiles(): ProfileServiceAsync.WithRawResponse = profiles
+
+ override fun tenants(): TenantServiceAsync.WithRawResponse = tenants
+
+ override fun translations(): TranslationServiceAsync.WithRawResponse = translations
+
+ override fun users(): UserServiceAsync.WithRawResponse = users
+ }
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientImpl.kt b/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientImpl.kt
new file mode 100644
index 00000000..9332ccdc
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/client/CourierClientImpl.kt
@@ -0,0 +1,247 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.api.client
+
+import com.courier.api.core.ClientOptions
+import com.courier.api.core.getPackageVersion
+import com.courier.api.services.blocking.AudienceService
+import com.courier.api.services.blocking.AudienceServiceImpl
+import com.courier.api.services.blocking.AuditEventService
+import com.courier.api.services.blocking.AuditEventServiceImpl
+import com.courier.api.services.blocking.AuthService
+import com.courier.api.services.blocking.AuthServiceImpl
+import com.courier.api.services.blocking.AutomationService
+import com.courier.api.services.blocking.AutomationServiceImpl
+import com.courier.api.services.blocking.BrandService
+import com.courier.api.services.blocking.BrandServiceImpl
+import com.courier.api.services.blocking.BulkService
+import com.courier.api.services.blocking.BulkServiceImpl
+import com.courier.api.services.blocking.InboundService
+import com.courier.api.services.blocking.InboundServiceImpl
+import com.courier.api.services.blocking.ListService
+import com.courier.api.services.blocking.ListServiceImpl
+import com.courier.api.services.blocking.MessageService
+import com.courier.api.services.blocking.MessageServiceImpl
+import com.courier.api.services.blocking.NotificationService
+import com.courier.api.services.blocking.NotificationServiceImpl
+import com.courier.api.services.blocking.ProfileService
+import com.courier.api.services.blocking.ProfileServiceImpl
+import com.courier.api.services.blocking.RequestService
+import com.courier.api.services.blocking.RequestServiceImpl
+import com.courier.api.services.blocking.SendService
+import com.courier.api.services.blocking.SendServiceImpl
+import com.courier.api.services.blocking.TenantService
+import com.courier.api.services.blocking.TenantServiceImpl
+import com.courier.api.services.blocking.TranslationService
+import com.courier.api.services.blocking.TranslationServiceImpl
+import com.courier.api.services.blocking.UserService
+import com.courier.api.services.blocking.UserServiceImpl
+import java.util.function.Consumer
+
+class CourierClientImpl(private val clientOptions: ClientOptions) : CourierClient {
+
+ private val clientOptionsWithUserAgent =
+ if (clientOptions.headers.names().contains("User-Agent")) clientOptions
+ else
+ clientOptions
+ .toBuilder()
+ .putHeader("User-Agent", "${javaClass.simpleName}/Java ${getPackageVersion()}")
+ .build()
+
+ // Pass the original clientOptions so that this client sets its own User-Agent.
+ private val async: CourierClientAsync by lazy { CourierClientAsyncImpl(clientOptions) }
+
+ private val withRawResponse: CourierClient.WithRawResponse by lazy {
+ WithRawResponseImpl(clientOptions)
+ }
+
+ private val send: SendService by lazy { SendServiceImpl(clientOptionsWithUserAgent) }
+
+ private val audiences: AudienceService by lazy {
+ AudienceServiceImpl(clientOptionsWithUserAgent)
+ }
+
+ private val auditEvents: AuditEventService by lazy {
+ AuditEventServiceImpl(clientOptionsWithUserAgent)
+ }
+
+ private val auth: AuthService by lazy { AuthServiceImpl(clientOptionsWithUserAgent) }
+
+ private val automations: AutomationService by lazy {
+ AutomationServiceImpl(clientOptionsWithUserAgent)
+ }
+
+ private val brands: BrandService by lazy { BrandServiceImpl(clientOptionsWithUserAgent) }
+
+ private val bulk: BulkService by lazy { BulkServiceImpl(clientOptionsWithUserAgent) }
+
+ private val inbound: InboundService by lazy { InboundServiceImpl(clientOptionsWithUserAgent) }
+
+ private val lists: ListService by lazy { ListServiceImpl(clientOptionsWithUserAgent) }
+
+ private val messages: MessageService by lazy { MessageServiceImpl(clientOptionsWithUserAgent) }
+
+ private val requests: RequestService by lazy { RequestServiceImpl(clientOptionsWithUserAgent) }
+
+ private val notifications: NotificationService by lazy {
+ NotificationServiceImpl(clientOptionsWithUserAgent)
+ }
+
+ private val profiles: ProfileService by lazy { ProfileServiceImpl(clientOptionsWithUserAgent) }
+
+ private val tenants: TenantService by lazy { TenantServiceImpl(clientOptionsWithUserAgent) }
+
+ private val translations: TranslationService by lazy {
+ TranslationServiceImpl(clientOptionsWithUserAgent)
+ }
+
+ private val users: UserService by lazy { UserServiceImpl(clientOptionsWithUserAgent) }
+
+ override fun async(): CourierClientAsync = async
+
+ override fun withRawResponse(): CourierClient.WithRawResponse = withRawResponse
+
+ override fun withOptions(modifier: Consumer): CourierClient =
+ CourierClientImpl(clientOptions.toBuilder().apply(modifier::accept).build())
+
+ override fun send(): SendService = send
+
+ override fun audiences(): AudienceService = audiences
+
+ override fun auditEvents(): AuditEventService = auditEvents
+
+ override fun auth(): AuthService = auth
+
+ override fun automations(): AutomationService = automations
+
+ override fun brands(): BrandService = brands
+
+ override fun bulk(): BulkService = bulk
+
+ override fun inbound(): InboundService = inbound
+
+ override fun lists(): ListService = lists
+
+ override fun messages(): MessageService = messages
+
+ override fun requests(): RequestService = requests
+
+ override fun notifications(): NotificationService = notifications
+
+ override fun profiles(): ProfileService = profiles
+
+ override fun tenants(): TenantService = tenants
+
+ override fun translations(): TranslationService = translations
+
+ override fun users(): UserService = users
+
+ override fun close() = clientOptions.close()
+
+ class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) :
+ CourierClient.WithRawResponse {
+
+ private val send: SendService.WithRawResponse by lazy {
+ SendServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val audiences: AudienceService.WithRawResponse by lazy {
+ AudienceServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val auditEvents: AuditEventService.WithRawResponse by lazy {
+ AuditEventServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val auth: AuthService.WithRawResponse by lazy {
+ AuthServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val automations: AutomationService.WithRawResponse by lazy {
+ AutomationServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val brands: BrandService.WithRawResponse by lazy {
+ BrandServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val bulk: BulkService.WithRawResponse by lazy {
+ BulkServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val inbound: InboundService.WithRawResponse by lazy {
+ InboundServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val lists: ListService.WithRawResponse by lazy {
+ ListServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val messages: MessageService.WithRawResponse by lazy {
+ MessageServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val requests: RequestService.WithRawResponse by lazy {
+ RequestServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val notifications: NotificationService.WithRawResponse by lazy {
+ NotificationServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val profiles: ProfileService.WithRawResponse by lazy {
+ ProfileServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val tenants: TenantService.WithRawResponse by lazy {
+ TenantServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val translations: TranslationService.WithRawResponse by lazy {
+ TranslationServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ private val users: UserService.WithRawResponse by lazy {
+ UserServiceImpl.WithRawResponseImpl(clientOptions)
+ }
+
+ override fun withOptions(
+ modifier: Consumer
+ ): CourierClient.WithRawResponse =
+ CourierClientImpl.WithRawResponseImpl(
+ clientOptions.toBuilder().apply(modifier::accept).build()
+ )
+
+ override fun send(): SendService.WithRawResponse = send
+
+ override fun audiences(): AudienceService.WithRawResponse = audiences
+
+ override fun auditEvents(): AuditEventService.WithRawResponse = auditEvents
+
+ override fun auth(): AuthService.WithRawResponse = auth
+
+ override fun automations(): AutomationService.WithRawResponse = automations
+
+ override fun brands(): BrandService.WithRawResponse = brands
+
+ override fun bulk(): BulkService.WithRawResponse = bulk
+
+ override fun inbound(): InboundService.WithRawResponse = inbound
+
+ override fun lists(): ListService.WithRawResponse = lists
+
+ override fun messages(): MessageService.WithRawResponse = messages
+
+ override fun requests(): RequestService.WithRawResponse = requests
+
+ override fun notifications(): NotificationService.WithRawResponse = notifications
+
+ override fun profiles(): ProfileService.WithRawResponse = profiles
+
+ override fun tenants(): TenantService.WithRawResponse = tenants
+
+ override fun translations(): TranslationService.WithRawResponse = translations
+
+ override fun users(): UserService.WithRawResponse = users
+ }
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/BaseDeserializer.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/BaseDeserializer.kt
new file mode 100644
index 00000000..6210d0dd
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/BaseDeserializer.kt
@@ -0,0 +1,44 @@
+package com.courier.api.core
+
+import com.fasterxml.jackson.core.JsonParser
+import com.fasterxml.jackson.core.ObjectCodec
+import com.fasterxml.jackson.core.type.TypeReference
+import com.fasterxml.jackson.databind.BeanProperty
+import com.fasterxml.jackson.databind.DeserializationContext
+import com.fasterxml.jackson.databind.JavaType
+import com.fasterxml.jackson.databind.JsonDeserializer
+import com.fasterxml.jackson.databind.JsonNode
+import com.fasterxml.jackson.databind.deser.ContextualDeserializer
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer
+import kotlin.reflect.KClass
+
+abstract class BaseDeserializer(type: KClass) :
+ StdDeserializer(type.java), ContextualDeserializer {
+
+ override fun createContextual(
+ context: DeserializationContext,
+ property: BeanProperty?,
+ ): JsonDeserializer {
+ return this
+ }
+
+ override fun deserialize(parser: JsonParser, context: DeserializationContext): T {
+ return parser.codec.deserialize(parser.readValueAsTree())
+ }
+
+ protected abstract fun ObjectCodec.deserialize(node: JsonNode): T
+
+ protected fun ObjectCodec.tryDeserialize(node: JsonNode, type: TypeReference): T? =
+ try {
+ readValue(treeAsTokens(node), type)
+ } catch (e: Exception) {
+ null
+ }
+
+ protected fun ObjectCodec.tryDeserialize(node: JsonNode, type: JavaType): T? =
+ try {
+ readValue(treeAsTokens(node), type)
+ } catch (e: Exception) {
+ null
+ }
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/BaseSerializer.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/BaseSerializer.kt
new file mode 100644
index 00000000..b62dd939
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/BaseSerializer.kt
@@ -0,0 +1,6 @@
+package com.courier.api.core
+
+import com.fasterxml.jackson.databind.ser.std.StdSerializer
+import kotlin.reflect.KClass
+
+abstract class BaseSerializer(type: KClass) : StdSerializer(type.java)
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/Check.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/Check.kt
new file mode 100644
index 00000000..c1e1eaf5
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/Check.kt
@@ -0,0 +1,96 @@
+@file:JvmName("Check")
+
+package com.courier.api.core
+
+import com.fasterxml.jackson.core.Version
+import com.fasterxml.jackson.core.util.VersionUtil
+
+fun checkRequired(name: String, condition: Boolean) =
+ check(condition) { "`$name` is required, but was not set" }
+
+fun checkRequired(name: String, value: T?): T =
+ checkNotNull(value) { "`$name` is required, but was not set" }
+
+@JvmSynthetic
+internal fun checkKnown(name: String, value: JsonField): T =
+ value.asKnown().orElseThrow {
+ IllegalStateException("`$name` is not a known type: ${value.javaClass.simpleName}")
+ }
+
+@JvmSynthetic
+internal fun checkKnown(name: String, value: MultipartField): T =
+ value.value.asKnown().orElseThrow {
+ IllegalStateException("`$name` is not a known type: ${value.javaClass.simpleName}")
+ }
+
+@JvmSynthetic
+internal fun checkLength(name: String, value: String, length: Int): String =
+ value.also {
+ check(it.length == length) { "`$name` must have length $length, but was ${it.length}" }
+ }
+
+@JvmSynthetic
+internal fun checkMinLength(name: String, value: String, minLength: Int): String =
+ value.also {
+ check(it.length >= minLength) {
+ if (minLength == 1) "`$name` must be non-empty, but was empty"
+ else "`$name` must have at least length $minLength, but was ${it.length}"
+ }
+ }
+
+@JvmSynthetic
+internal fun checkMaxLength(name: String, value: String, maxLength: Int): String =
+ value.also {
+ check(it.length <= maxLength) {
+ "`$name` must have at most length $maxLength, but was ${it.length}"
+ }
+ }
+
+@JvmSynthetic
+internal fun checkJacksonVersionCompatibility() {
+ val incompatibleJacksonVersions =
+ RUNTIME_JACKSON_VERSIONS.mapNotNull {
+ val badVersionReason = BAD_JACKSON_VERSIONS[it.toString()]
+ when {
+ it.majorVersion != MINIMUM_JACKSON_VERSION.majorVersion ->
+ it to "incompatible major version"
+ it.minorVersion < MINIMUM_JACKSON_VERSION.minorVersion ->
+ it to "minor version too low"
+ it.minorVersion == MINIMUM_JACKSON_VERSION.minorVersion &&
+ it.patchLevel < MINIMUM_JACKSON_VERSION.patchLevel ->
+ it to "patch version too low"
+ badVersionReason != null -> it to badVersionReason
+ else -> null
+ }
+ }
+ check(incompatibleJacksonVersions.isEmpty()) {
+ """
+This SDK requires a minimum Jackson version of $MINIMUM_JACKSON_VERSION, but the following incompatible Jackson versions were detected at runtime:
+
+${incompatibleJacksonVersions.asSequence().map { (version, incompatibilityReason) ->
+ "- `${version.toFullString().replace("/", ":")}` ($incompatibilityReason)"
+}.joinToString("\n")}
+
+This can happen if you are either:
+1. Directly depending on different Jackson versions
+2. Depending on some library that depends on different Jackson versions, potentially transitively
+
+Double-check that you are depending on compatible Jackson versions.
+
+See https://www.github.com/stainless-sdks/courier-java#jackson for more information.
+ """
+ .trimIndent()
+ }
+}
+
+private val MINIMUM_JACKSON_VERSION: Version = VersionUtil.parseVersion("2.13.4", null, null)
+private val BAD_JACKSON_VERSIONS: Map =
+ mapOf("2.18.1" to "due to https://github.com/FasterXML/jackson-databind/issues/4639")
+private val RUNTIME_JACKSON_VERSIONS: List =
+ listOf(
+ com.fasterxml.jackson.core.json.PackageVersion.VERSION,
+ com.fasterxml.jackson.databind.cfg.PackageVersion.VERSION,
+ com.fasterxml.jackson.datatype.jdk8.PackageVersion.VERSION,
+ com.fasterxml.jackson.datatype.jsr310.PackageVersion.VERSION,
+ com.fasterxml.jackson.module.kotlin.PackageVersion.VERSION,
+ )
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/ClientOptions.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/ClientOptions.kt
new file mode 100644
index 00000000..232898e7
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/ClientOptions.kt
@@ -0,0 +1,450 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.api.core
+
+import com.courier.api.core.http.Headers
+import com.courier.api.core.http.HttpClient
+import com.courier.api.core.http.PhantomReachableClosingHttpClient
+import com.courier.api.core.http.QueryParams
+import com.courier.api.core.http.RetryingHttpClient
+import com.fasterxml.jackson.databind.json.JsonMapper
+import java.time.Clock
+import java.time.Duration
+import java.util.Optional
+import kotlin.jvm.optionals.getOrNull
+
+/** A class representing the SDK client configuration. */
+class ClientOptions
+private constructor(
+ private val originalHttpClient: HttpClient,
+ /**
+ * The HTTP client to use in the SDK.
+ *
+ * Use the one published in `courier-java-client-okhttp` or implement your own.
+ *
+ * This class takes ownership of the client and closes it when closed.
+ */
+ @get:JvmName("httpClient") val httpClient: HttpClient,
+ /**
+ * Whether to throw an exception if any of the Jackson versions detected at runtime are
+ * incompatible with the SDK's minimum supported Jackson version (2.13.4).
+ *
+ * Defaults to true. Use extreme caution when disabling this option. There is no guarantee that
+ * the SDK will work correctly when using an incompatible Jackson version.
+ */
+ @get:JvmName("checkJacksonVersionCompatibility") val checkJacksonVersionCompatibility: Boolean,
+ /**
+ * The Jackson JSON mapper to use for serializing and deserializing JSON.
+ *
+ * Defaults to [com.courier.api.core.jsonMapper]. The default is usually sufficient and rarely
+ * needs to be overridden.
+ */
+ @get:JvmName("jsonMapper") val jsonMapper: JsonMapper,
+ /**
+ * The interface to use for delaying execution, like during retries.
+ *
+ * This is primarily useful for using fake delays in tests.
+ *
+ * Defaults to real execution delays.
+ *
+ * This class takes ownership of the sleeper and closes it when closed.
+ */
+ @get:JvmName("sleeper") val sleeper: Sleeper,
+ /**
+ * The clock to use for operations that require timing, like retries.
+ *
+ * This is primarily useful for using a fake clock in tests.
+ *
+ * Defaults to [Clock.systemUTC].
+ */
+ @get:JvmName("clock") val clock: Clock,
+ private val baseUrl: String?,
+ /** Headers to send with the request. */
+ @get:JvmName("headers") val headers: Headers,
+ /** Query params to send with the request. */
+ @get:JvmName("queryParams") val queryParams: QueryParams,
+ /**
+ * Whether to call `validate` on every response before returning it.
+ *
+ * Defaults to false, which means the shape of the response will not be validated upfront.
+ * Instead, validation will only occur for the parts of the response that are accessed.
+ */
+ @get:JvmName("responseValidation") val responseValidation: Boolean,
+ /**
+ * Sets the maximum time allowed for various parts of an HTTP call's lifecycle, excluding
+ * retries.
+ *
+ * Defaults to [Timeout.default].
+ */
+ @get:JvmName("timeout") val timeout: Timeout,
+ /**
+ * The maximum number of times to retry failed requests, with a short exponential backoff
+ * between requests.
+ *
+ * Only the following error types are retried:
+ * - Connection errors (for example, due to a network connectivity problem)
+ * - 408 Request Timeout
+ * - 409 Conflict
+ * - 429 Rate Limit
+ * - 5xx Internal
+ *
+ * The API may also explicitly instruct the SDK to retry or not retry a request.
+ *
+ * Defaults to 2.
+ */
+ @get:JvmName("maxRetries") val maxRetries: Int,
+ @get:JvmName("apiKey") val apiKey: String,
+) {
+
+ init {
+ if (checkJacksonVersionCompatibility) {
+ checkJacksonVersionCompatibility()
+ }
+ }
+
+ /**
+ * The base URL to use for every request.
+ *
+ * Defaults to the production environment: `https://api.courier.com`.
+ */
+ fun baseUrl(): String = baseUrl ?: PRODUCTION_URL
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ const val PRODUCTION_URL = "https://api.courier.com"
+
+ /**
+ * Returns a mutable builder for constructing an instance of [ClientOptions].
+ *
+ * The following fields are required:
+ * ```java
+ * .httpClient()
+ * .apiKey()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+
+ /**
+ * Returns options configured using system properties and environment variables.
+ *
+ * @see Builder.fromEnv
+ */
+ @JvmStatic fun fromEnv(): ClientOptions = builder().fromEnv().build()
+ }
+
+ /** A builder for [ClientOptions]. */
+ class Builder internal constructor() {
+
+ private var httpClient: HttpClient? = null
+ private var checkJacksonVersionCompatibility: Boolean = true
+ private var jsonMapper: JsonMapper = jsonMapper()
+ private var sleeper: Sleeper? = null
+ private var clock: Clock = Clock.systemUTC()
+ private var baseUrl: String? = null
+ private var headers: Headers.Builder = Headers.builder()
+ private var queryParams: QueryParams.Builder = QueryParams.builder()
+ private var responseValidation: Boolean = false
+ private var timeout: Timeout = Timeout.default()
+ private var maxRetries: Int = 2
+ private var apiKey: String? = null
+
+ @JvmSynthetic
+ internal fun from(clientOptions: ClientOptions) = apply {
+ httpClient = clientOptions.originalHttpClient
+ checkJacksonVersionCompatibility = clientOptions.checkJacksonVersionCompatibility
+ jsonMapper = clientOptions.jsonMapper
+ sleeper = clientOptions.sleeper
+ clock = clientOptions.clock
+ baseUrl = clientOptions.baseUrl
+ headers = clientOptions.headers.toBuilder()
+ queryParams = clientOptions.queryParams.toBuilder()
+ responseValidation = clientOptions.responseValidation
+ timeout = clientOptions.timeout
+ maxRetries = clientOptions.maxRetries
+ apiKey = clientOptions.apiKey
+ }
+
+ /**
+ * The HTTP client to use in the SDK.
+ *
+ * Use the one published in `courier-java-client-okhttp` or implement your own.
+ *
+ * This class takes ownership of the client and closes it when closed.
+ */
+ fun httpClient(httpClient: HttpClient) = apply {
+ this.httpClient = PhantomReachableClosingHttpClient(httpClient)
+ }
+
+ /**
+ * Whether to throw an exception if any of the Jackson versions detected at runtime are
+ * incompatible with the SDK's minimum supported Jackson version (2.13.4).
+ *
+ * Defaults to true. Use extreme caution when disabling this option. There is no guarantee
+ * that the SDK will work correctly when using an incompatible Jackson version.
+ */
+ fun checkJacksonVersionCompatibility(checkJacksonVersionCompatibility: Boolean) = apply {
+ this.checkJacksonVersionCompatibility = checkJacksonVersionCompatibility
+ }
+
+ /**
+ * The Jackson JSON mapper to use for serializing and deserializing JSON.
+ *
+ * Defaults to [com.courier.api.core.jsonMapper]. The default is usually sufficient and
+ * rarely needs to be overridden.
+ */
+ fun jsonMapper(jsonMapper: JsonMapper) = apply { this.jsonMapper = jsonMapper }
+
+ /**
+ * The interface to use for delaying execution, like during retries.
+ *
+ * This is primarily useful for using fake delays in tests.
+ *
+ * Defaults to real execution delays.
+ *
+ * This class takes ownership of the sleeper and closes it when closed.
+ */
+ fun sleeper(sleeper: Sleeper) = apply { this.sleeper = PhantomReachableSleeper(sleeper) }
+
+ /**
+ * The clock to use for operations that require timing, like retries.
+ *
+ * This is primarily useful for using a fake clock in tests.
+ *
+ * Defaults to [Clock.systemUTC].
+ */
+ fun clock(clock: Clock) = apply { this.clock = clock }
+
+ /**
+ * The base URL to use for every request.
+ *
+ * Defaults to the production environment: `https://api.courier.com`.
+ */
+ fun baseUrl(baseUrl: String?) = apply { this.baseUrl = baseUrl }
+
+ /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */
+ fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull())
+
+ /**
+ * Whether to call `validate` on every response before returning it.
+ *
+ * Defaults to false, which means the shape of the response will not be validated upfront.
+ * Instead, validation will only occur for the parts of the response that are accessed.
+ */
+ fun responseValidation(responseValidation: Boolean) = apply {
+ this.responseValidation = responseValidation
+ }
+
+ /**
+ * Sets the maximum time allowed for various parts of an HTTP call's lifecycle, excluding
+ * retries.
+ *
+ * Defaults to [Timeout.default].
+ */
+ fun timeout(timeout: Timeout) = apply { this.timeout = timeout }
+
+ /**
+ * Sets the maximum time allowed for a complete HTTP call, not including retries.
+ *
+ * See [Timeout.request] for more details.
+ *
+ * For fine-grained control, pass a [Timeout] object.
+ */
+ fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build())
+
+ /**
+ * The maximum number of times to retry failed requests, with a short exponential backoff
+ * between requests.
+ *
+ * Only the following error types are retried:
+ * - Connection errors (for example, due to a network connectivity problem)
+ * - 408 Request Timeout
+ * - 409 Conflict
+ * - 429 Rate Limit
+ * - 5xx Internal
+ *
+ * The API may also explicitly instruct the SDK to retry or not retry a request.
+ *
+ * Defaults to 2.
+ */
+ fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries }
+
+ fun apiKey(apiKey: String) = apply { this.apiKey = apiKey }
+
+ fun headers(headers: Headers) = apply {
+ this.headers.clear()
+ putAllHeaders(headers)
+ }
+
+ fun headers(headers: Map>) = apply {
+ this.headers.clear()
+ putAllHeaders(headers)
+ }
+
+ fun putHeader(name: String, value: String) = apply { headers.put(name, value) }
+
+ fun putHeaders(name: String, values: Iterable) = apply { headers.put(name, values) }
+
+ fun putAllHeaders(headers: Headers) = apply { this.headers.putAll(headers) }
+
+ fun putAllHeaders(headers: Map>) = apply {
+ this.headers.putAll(headers)
+ }
+
+ fun replaceHeaders(name: String, value: String) = apply { headers.replace(name, value) }
+
+ fun replaceHeaders(name: String, values: Iterable) = apply {
+ headers.replace(name, values)
+ }
+
+ fun replaceAllHeaders(headers: Headers) = apply { this.headers.replaceAll(headers) }
+
+ fun replaceAllHeaders(headers: Map>) = apply {
+ this.headers.replaceAll(headers)
+ }
+
+ fun removeHeaders(name: String) = apply { headers.remove(name) }
+
+ fun removeAllHeaders(names: Set) = apply { headers.removeAll(names) }
+
+ fun queryParams(queryParams: QueryParams) = apply {
+ this.queryParams.clear()
+ putAllQueryParams(queryParams)
+ }
+
+ fun queryParams(queryParams: Map>) = apply {
+ this.queryParams.clear()
+ putAllQueryParams(queryParams)
+ }
+
+ fun putQueryParam(key: String, value: String) = apply { queryParams.put(key, value) }
+
+ fun putQueryParams(key: String, values: Iterable) = apply {
+ queryParams.put(key, values)
+ }
+
+ fun putAllQueryParams(queryParams: QueryParams) = apply {
+ this.queryParams.putAll(queryParams)
+ }
+
+ fun putAllQueryParams(queryParams: Map>) = apply {
+ this.queryParams.putAll(queryParams)
+ }
+
+ fun replaceQueryParams(key: String, value: String) = apply {
+ queryParams.replace(key, value)
+ }
+
+ fun replaceQueryParams(key: String, values: Iterable) = apply {
+ queryParams.replace(key, values)
+ }
+
+ fun replaceAllQueryParams(queryParams: QueryParams) = apply {
+ this.queryParams.replaceAll(queryParams)
+ }
+
+ fun replaceAllQueryParams(queryParams: Map>) = apply {
+ this.queryParams.replaceAll(queryParams)
+ }
+
+ fun removeQueryParams(key: String) = apply { queryParams.remove(key) }
+
+ fun removeAllQueryParams(keys: Set) = apply { queryParams.removeAll(keys) }
+
+ fun timeout(): Timeout = timeout
+
+ /**
+ * Updates configuration using system properties and environment variables.
+ *
+ * See this table for the available options:
+ *
+ * |Setter |System property |Environment variable|Required|Default value |
+ * |---------|-----------------|--------------------|--------|---------------------------|
+ * |`apiKey` |`courier.apiKey` |`COURIER_API_KEY` |true |- |
+ * |`baseUrl`|`courier.baseUrl`|`COURIER_BASE_URL` |true |`"https://api.courier.com"`|
+ *
+ * System properties take precedence over environment variables.
+ */
+ fun fromEnv() = apply {
+ (System.getProperty("courier.baseUrl") ?: System.getenv("COURIER_BASE_URL"))?.let {
+ baseUrl(it)
+ }
+ (System.getProperty("courier.apiKey") ?: System.getenv("COURIER_API_KEY"))?.let {
+ apiKey(it)
+ }
+ }
+
+ /**
+ * Returns an immutable instance of [ClientOptions].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .httpClient()
+ * .apiKey()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): ClientOptions {
+ val httpClient = checkRequired("httpClient", httpClient)
+ val sleeper = sleeper ?: PhantomReachableSleeper(DefaultSleeper())
+ val apiKey = checkRequired("apiKey", apiKey)
+
+ val headers = Headers.builder()
+ val queryParams = QueryParams.builder()
+ headers.put("X-Stainless-Lang", "java")
+ headers.put("X-Stainless-Arch", getOsArch())
+ headers.put("X-Stainless-OS", getOsName())
+ headers.put("X-Stainless-OS-Version", getOsVersion())
+ headers.put("X-Stainless-Package-Version", getPackageVersion())
+ headers.put("X-Stainless-Runtime", "JRE")
+ headers.put("X-Stainless-Runtime-Version", getJavaVersion())
+ apiKey.let {
+ if (!it.isEmpty()) {
+ headers.put("Authorization", "Bearer $it")
+ }
+ }
+ headers.replaceAll(this.headers.build())
+ queryParams.replaceAll(this.queryParams.build())
+
+ return ClientOptions(
+ httpClient,
+ RetryingHttpClient.builder()
+ .httpClient(httpClient)
+ .sleeper(sleeper)
+ .clock(clock)
+ .maxRetries(maxRetries)
+ .build(),
+ checkJacksonVersionCompatibility,
+ jsonMapper,
+ sleeper,
+ clock,
+ baseUrl,
+ headers.build(),
+ queryParams.build(),
+ responseValidation,
+ timeout,
+ maxRetries,
+ apiKey,
+ )
+ }
+ }
+
+ /**
+ * Closes these client options, relinquishing any underlying resources.
+ *
+ * This is purposefully not inherited from [AutoCloseable] because the client options are
+ * long-lived and usually should not be synchronously closed via try-with-resources.
+ *
+ * It's also usually not necessary to call this method at all. the default client automatically
+ * releases threads and connections if they remain idle, but if you are writing an application
+ * that needs to aggressively release unused resources, then you may call this method.
+ */
+ fun close() {
+ httpClient.close()
+ sleeper.close()
+ }
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/DefaultSleeper.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/DefaultSleeper.kt
new file mode 100644
index 00000000..e068e204
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/DefaultSleeper.kt
@@ -0,0 +1,28 @@
+package com.courier.api.core
+
+import java.time.Duration
+import java.util.Timer
+import java.util.TimerTask
+import java.util.concurrent.CompletableFuture
+
+class DefaultSleeper : Sleeper {
+
+ private val timer = Timer("DefaultSleeper", true)
+
+ override fun sleep(duration: Duration) = Thread.sleep(duration.toMillis())
+
+ override fun sleepAsync(duration: Duration): CompletableFuture {
+ val future = CompletableFuture()
+ timer.schedule(
+ object : TimerTask() {
+ override fun run() {
+ future.complete(null)
+ }
+ },
+ duration.toMillis(),
+ )
+ return future
+ }
+
+ override fun close() = timer.cancel()
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/ObjectMappers.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/ObjectMappers.kt
new file mode 100644
index 00000000..5cfc46de
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/ObjectMappers.kt
@@ -0,0 +1,167 @@
+@file:JvmName("ObjectMappers")
+
+package com.courier.api.core
+
+import com.fasterxml.jackson.annotation.JsonInclude
+import com.fasterxml.jackson.core.JsonGenerator
+import com.fasterxml.jackson.core.JsonParseException
+import com.fasterxml.jackson.core.JsonParser
+import com.fasterxml.jackson.databind.DeserializationContext
+import com.fasterxml.jackson.databind.DeserializationFeature
+import com.fasterxml.jackson.databind.MapperFeature
+import com.fasterxml.jackson.databind.SerializationFeature
+import com.fasterxml.jackson.databind.SerializerProvider
+import com.fasterxml.jackson.databind.cfg.CoercionAction
+import com.fasterxml.jackson.databind.cfg.CoercionInputShape
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer
+import com.fasterxml.jackson.databind.json.JsonMapper
+import com.fasterxml.jackson.databind.module.SimpleModule
+import com.fasterxml.jackson.databind.type.LogicalType
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
+import com.fasterxml.jackson.module.kotlin.kotlinModule
+import java.io.InputStream
+import java.time.DateTimeException
+import java.time.LocalDate
+import java.time.LocalDateTime
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+import java.time.temporal.ChronoField
+
+fun jsonMapper(): JsonMapper =
+ JsonMapper.builder()
+ .addModule(kotlinModule())
+ .addModule(Jdk8Module())
+ .addModule(JavaTimeModule())
+ .addModule(
+ SimpleModule()
+ .addSerializer(InputStreamSerializer)
+ .addDeserializer(LocalDateTime::class.java, LenientLocalDateTimeDeserializer())
+ )
+ .withCoercionConfig(LogicalType.Boolean) {
+ it.setCoercion(CoercionInputShape.Integer, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Float, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.String, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Array, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Object, CoercionAction.Fail)
+ }
+ .withCoercionConfig(LogicalType.Integer) {
+ it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.String, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Array, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Object, CoercionAction.Fail)
+ }
+ .withCoercionConfig(LogicalType.Float) {
+ it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.String, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Array, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Object, CoercionAction.Fail)
+ }
+ .withCoercionConfig(LogicalType.Textual) {
+ it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Float, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Array, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Object, CoercionAction.Fail)
+ }
+ .withCoercionConfig(LogicalType.Array) {
+ it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Float, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.String, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Object, CoercionAction.Fail)
+ }
+ .withCoercionConfig(LogicalType.Collection) {
+ it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Float, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.String, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Object, CoercionAction.Fail)
+ }
+ .withCoercionConfig(LogicalType.Map) {
+ it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Float, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.String, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Object, CoercionAction.Fail)
+ }
+ .withCoercionConfig(LogicalType.POJO) {
+ it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Float, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.String, CoercionAction.Fail)
+ .setCoercion(CoercionInputShape.Array, CoercionAction.Fail)
+ }
+ .serializationInclusion(JsonInclude.Include.NON_ABSENT)
+ .disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
+ .disable(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)
+ .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
+ .disable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS)
+ .disable(MapperFeature.ALLOW_COERCION_OF_SCALARS)
+ .disable(MapperFeature.AUTO_DETECT_CREATORS)
+ .disable(MapperFeature.AUTO_DETECT_FIELDS)
+ .disable(MapperFeature.AUTO_DETECT_GETTERS)
+ .disable(MapperFeature.AUTO_DETECT_IS_GETTERS)
+ .disable(MapperFeature.AUTO_DETECT_SETTERS)
+ .build()
+
+/** A serializer that serializes [InputStream] to bytes. */
+private object InputStreamSerializer : BaseSerializer(InputStream::class) {
+
+ private fun readResolve(): Any = InputStreamSerializer
+
+ override fun serialize(
+ value: InputStream?,
+ gen: JsonGenerator?,
+ serializers: SerializerProvider?,
+ ) {
+ if (value == null) {
+ gen?.writeNull()
+ } else {
+ value.use { gen?.writeBinary(it.readBytes()) }
+ }
+ }
+}
+
+/**
+ * A deserializer that can deserialize [LocalDateTime] from datetimes, dates, and zoned datetimes.
+ */
+private class LenientLocalDateTimeDeserializer :
+ StdDeserializer(LocalDateTime::class.java) {
+
+ companion object {
+
+ private val DATE_TIME_FORMATTERS =
+ listOf(
+ DateTimeFormatter.ISO_LOCAL_DATE_TIME,
+ DateTimeFormatter.ISO_LOCAL_DATE,
+ DateTimeFormatter.ISO_ZONED_DATE_TIME,
+ )
+ }
+
+ override fun logicalType(): LogicalType = LogicalType.DateTime
+
+ override fun deserialize(p: JsonParser, context: DeserializationContext?): LocalDateTime {
+ val exceptions = mutableListOf()
+
+ for (formatter in DATE_TIME_FORMATTERS) {
+ try {
+ val temporal = formatter.parse(p.text)
+
+ return when {
+ !temporal.isSupported(ChronoField.HOUR_OF_DAY) ->
+ LocalDate.from(temporal).atStartOfDay()
+ !temporal.isSupported(ChronoField.OFFSET_SECONDS) ->
+ LocalDateTime.from(temporal)
+ else -> ZonedDateTime.from(temporal).toLocalDateTime()
+ }
+ } catch (e: DateTimeException) {
+ exceptions.add(e)
+ }
+ }
+
+ throw JsonParseException(p, "Cannot parse `LocalDateTime` from value: ${p.text}").apply {
+ exceptions.forEach { addSuppressed(it) }
+ }
+ }
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/Params.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/Params.kt
new file mode 100644
index 00000000..a04c55b9
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/Params.kt
@@ -0,0 +1,16 @@
+package com.courier.api.core
+
+import com.courier.api.core.http.Headers
+import com.courier.api.core.http.QueryParams
+
+/** An interface representing parameters passed to a service method. */
+interface Params {
+ /** The full set of headers in the parameters, including both fixed and additional headers. */
+ fun _headers(): Headers
+
+ /**
+ * The full set of query params in the parameters, including both fixed and additional query
+ * params.
+ */
+ fun _queryParams(): QueryParams
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachable.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachable.kt
new file mode 100644
index 00000000..42ae140e
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachable.kt
@@ -0,0 +1,56 @@
+@file:JvmName("PhantomReachable")
+
+package com.courier.api.core
+
+import com.courier.api.errors.CourierException
+import java.lang.reflect.InvocationTargetException
+
+/**
+ * Closes [closeable] when [observed] becomes only phantom reachable.
+ *
+ * This is a wrapper around a Java 9+ [java.lang.ref.Cleaner], or a no-op in older Java versions.
+ */
+@JvmSynthetic
+internal fun closeWhenPhantomReachable(observed: Any, closeable: AutoCloseable) {
+ check(observed !== closeable) {
+ "`observed` cannot be the same object as `closeable` because it would never become phantom reachable"
+ }
+ closeWhenPhantomReachable(observed, closeable::close)
+}
+
+/**
+ * Calls [close] when [observed] becomes only phantom reachable.
+ *
+ * This is a wrapper around a Java 9+ [java.lang.ref.Cleaner], or a no-op in older Java versions.
+ */
+@JvmSynthetic
+internal fun closeWhenPhantomReachable(observed: Any, close: () -> Unit) {
+ closeWhenPhantomReachable?.let { it(observed, close) }
+}
+
+private val closeWhenPhantomReachable: ((Any, () -> Unit) -> Unit)? by lazy {
+ try {
+ val cleanerClass = Class.forName("java.lang.ref.Cleaner")
+ val cleanerCreate = cleanerClass.getMethod("create")
+ val cleanerRegister =
+ cleanerClass.getMethod("register", Any::class.java, Runnable::class.java)
+ val cleanerObject = cleanerCreate.invoke(null);
+
+ { observed, close ->
+ try {
+ cleanerRegister.invoke(cleanerObject, observed, Runnable { close() })
+ } catch (e: ReflectiveOperationException) {
+ if (e is InvocationTargetException) {
+ when (val cause = e.cause) {
+ is RuntimeException,
+ is Error -> throw cause
+ }
+ }
+ throw CourierException("Unexpected reflective invocation failure", e)
+ }
+ }
+ } catch (e: ReflectiveOperationException) {
+ // We're running Java 8, which has no Cleaner.
+ null
+ }
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachableExecutorService.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachableExecutorService.kt
new file mode 100644
index 00000000..20e6c410
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachableExecutorService.kt
@@ -0,0 +1,58 @@
+package com.courier.api.core
+
+import java.util.concurrent.Callable
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Future
+import java.util.concurrent.TimeUnit
+
+/**
+ * A delegating wrapper around an [ExecutorService] that shuts it down once it's only phantom
+ * reachable.
+ *
+ * This class ensures the [ExecutorService] is shut down even if the user forgets to do it.
+ */
+internal class PhantomReachableExecutorService(private val executorService: ExecutorService) :
+ ExecutorService {
+ init {
+ closeWhenPhantomReachable(this) { executorService.shutdown() }
+ }
+
+ override fun execute(command: Runnable) = executorService.execute(command)
+
+ override fun shutdown() = executorService.shutdown()
+
+ override fun shutdownNow(): MutableList = executorService.shutdownNow()
+
+ override fun isShutdown(): Boolean = executorService.isShutdown
+
+ override fun isTerminated(): Boolean = executorService.isTerminated
+
+ override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean =
+ executorService.awaitTermination(timeout, unit)
+
+ override fun submit(task: Callable): Future = executorService.submit(task)
+
+ override fun submit(task: Runnable, result: T): Future =
+ executorService.submit(task, result)
+
+ override fun submit(task: Runnable): Future<*> = executorService.submit(task)
+
+ override fun invokeAll(
+ tasks: MutableCollection>
+ ): MutableList> = executorService.invokeAll(tasks)
+
+ override fun invokeAll(
+ tasks: MutableCollection>,
+ timeout: Long,
+ unit: TimeUnit,
+ ): MutableList> = executorService.invokeAll(tasks, timeout, unit)
+
+ override fun invokeAny(tasks: MutableCollection>): T =
+ executorService.invokeAny(tasks)
+
+ override fun invokeAny(
+ tasks: MutableCollection>,
+ timeout: Long,
+ unit: TimeUnit,
+ ): T = executorService.invokeAny(tasks, timeout, unit)
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachableSleeper.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachableSleeper.kt
new file mode 100644
index 00000000..6af9d159
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/PhantomReachableSleeper.kt
@@ -0,0 +1,23 @@
+package com.courier.api.core
+
+import java.time.Duration
+import java.util.concurrent.CompletableFuture
+
+/**
+ * A delegating wrapper around a [Sleeper] that closes it once it's only phantom reachable.
+ *
+ * This class ensures the [Sleeper] is closed even if the user forgets to do it.
+ */
+internal class PhantomReachableSleeper(private val sleeper: Sleeper) : Sleeper {
+
+ init {
+ closeWhenPhantomReachable(this, sleeper)
+ }
+
+ override fun sleep(duration: Duration) = sleeper.sleep(duration)
+
+ override fun sleepAsync(duration: Duration): CompletableFuture =
+ sleeper.sleepAsync(duration)
+
+ override fun close() = sleeper.close()
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/PrepareRequest.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/PrepareRequest.kt
new file mode 100644
index 00000000..0864d52b
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/PrepareRequest.kt
@@ -0,0 +1,24 @@
+@file:JvmName("PrepareRequest")
+
+package com.courier.api.core
+
+import com.courier.api.core.http.HttpRequest
+import java.util.concurrent.CompletableFuture
+
+@JvmSynthetic
+internal fun HttpRequest.prepare(clientOptions: ClientOptions, params: Params): HttpRequest =
+ toBuilder()
+ .putAllQueryParams(clientOptions.queryParams)
+ .replaceAllQueryParams(params._queryParams())
+ .putAllHeaders(clientOptions.headers)
+ .replaceAllHeaders(params._headers())
+ .build()
+
+@JvmSynthetic
+internal fun HttpRequest.prepareAsync(
+ clientOptions: ClientOptions,
+ params: Params,
+): CompletableFuture =
+ // This async version exists to make it easier to add async specific preparation logic in the
+ // future.
+ CompletableFuture.completedFuture(prepare(clientOptions, params))
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/Properties.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/Properties.kt
new file mode 100644
index 00000000..e2c8c5f6
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/Properties.kt
@@ -0,0 +1,42 @@
+@file:JvmName("Properties")
+
+package com.courier.api.core
+
+import com.courier.api.client.CourierClient
+
+fun getOsArch(): String {
+ val osArch = System.getProperty("os.arch")
+
+ return when (osArch) {
+ null -> "unknown"
+ "i386",
+ "x32",
+ "x86" -> "x32"
+ "amd64",
+ "x86_64" -> "x64"
+ "arm" -> "arm"
+ "aarch64" -> "arm64"
+ else -> "other:$osArch"
+ }
+}
+
+fun getOsName(): String {
+ val osName = System.getProperty("os.name")
+ val vendorUrl = System.getProperty("java.vendor.url")
+
+ return when {
+ osName == null -> "Unknown"
+ osName.startsWith("Linux") && vendorUrl == "http://www.android.com/" -> "Android"
+ osName.startsWith("Linux") -> "Linux"
+ osName.startsWith("Mac OS") -> "MacOS"
+ osName.startsWith("Windows") -> "Windows"
+ else -> "Other:$osName"
+ }
+}
+
+fun getOsVersion(): String = System.getProperty("os.version", "unknown")
+
+fun getPackageVersion(): String =
+ CourierClient::class.java.`package`.implementationVersion ?: "unknown"
+
+fun getJavaVersion(): String = System.getProperty("java.version", "unknown")
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/RequestOptions.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/RequestOptions.kt
new file mode 100644
index 00000000..40194eea
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/RequestOptions.kt
@@ -0,0 +1,46 @@
+package com.courier.api.core
+
+import java.time.Duration
+
+class RequestOptions private constructor(val responseValidation: Boolean?, val timeout: Timeout?) {
+
+ companion object {
+
+ private val NONE = builder().build()
+
+ @JvmStatic fun none() = NONE
+
+ @JvmSynthetic
+ internal fun from(clientOptions: ClientOptions): RequestOptions =
+ builder()
+ .responseValidation(clientOptions.responseValidation)
+ .timeout(clientOptions.timeout)
+ .build()
+
+ @JvmStatic fun builder() = Builder()
+ }
+
+ fun applyDefaults(options: RequestOptions): RequestOptions =
+ RequestOptions(
+ responseValidation = responseValidation ?: options.responseValidation,
+ timeout =
+ if (options.timeout != null && timeout != null) timeout.assign(options.timeout)
+ else timeout ?: options.timeout,
+ )
+
+ class Builder internal constructor() {
+
+ private var responseValidation: Boolean? = null
+ private var timeout: Timeout? = null
+
+ fun responseValidation(responseValidation: Boolean) = apply {
+ this.responseValidation = responseValidation
+ }
+
+ fun timeout(timeout: Timeout) = apply { this.timeout = timeout }
+
+ fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build())
+
+ fun build(): RequestOptions = RequestOptions(responseValidation, timeout)
+ }
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/Sleeper.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/Sleeper.kt
new file mode 100644
index 00000000..3289f942
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/Sleeper.kt
@@ -0,0 +1,21 @@
+package com.courier.api.core
+
+import java.time.Duration
+import java.util.concurrent.CompletableFuture
+
+/**
+ * An interface for delaying execution for a specified amount of time.
+ *
+ * Useful for testing and cleaning up resources.
+ */
+interface Sleeper : AutoCloseable {
+
+ /** Synchronously pauses execution for the given [duration]. */
+ fun sleep(duration: Duration)
+
+ /** Asynchronously pauses execution for the given [duration]. */
+ fun sleepAsync(duration: Duration): CompletableFuture
+
+ /** Overridden from [AutoCloseable] to not have a checked exception in its signature. */
+ override fun close()
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/Timeout.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/Timeout.kt
new file mode 100644
index 00000000..614a6434
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/Timeout.kt
@@ -0,0 +1,171 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package com.courier.api.core
+
+import java.time.Duration
+import java.util.Objects
+import java.util.Optional
+import kotlin.jvm.optionals.getOrNull
+
+/** A class containing timeouts for various processing phases of a request. */
+class Timeout
+private constructor(
+ private val connect: Duration?,
+ private val read: Duration?,
+ private val write: Duration?,
+ private val request: Duration?,
+) {
+
+ /**
+ * The maximum time allowed to establish a connection with a host.
+ *
+ * A value of [Duration.ZERO] means there's no timeout.
+ *
+ * Defaults to `Duration.ofMinutes(1)`.
+ */
+ fun connect(): Duration = connect ?: Duration.ofMinutes(1)
+
+ /**
+ * The maximum time allowed between two data packets when waiting for the server’s response.
+ *
+ * A value of [Duration.ZERO] means there's no timeout.
+ *
+ * Defaults to `request()`.
+ */
+ fun read(): Duration = read ?: request()
+
+ /**
+ * The maximum time allowed between two data packets when sending the request to the server.
+ *
+ * A value of [Duration.ZERO] means there's no timeout.
+ *
+ * Defaults to `request()`.
+ */
+ fun write(): Duration = write ?: request()
+
+ /**
+ * The maximum time allowed for a complete HTTP call, not including retries.
+ *
+ * This includes resolving DNS, connecting, writing the request body, server processing, as well
+ * as reading the response body.
+ *
+ * A value of [Duration.ZERO] means there's no timeout.
+ *
+ * Defaults to `Duration.ofMinutes(1)`.
+ */
+ fun request(): Duration = request ?: Duration.ofMinutes(1)
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ @JvmStatic fun default() = builder().build()
+
+ /** Returns a mutable builder for constructing an instance of [Timeout]. */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [Timeout]. */
+ class Builder internal constructor() {
+
+ private var connect: Duration? = null
+ private var read: Duration? = null
+ private var write: Duration? = null
+ private var request: Duration? = null
+
+ @JvmSynthetic
+ internal fun from(timeout: Timeout) = apply {
+ connect = timeout.connect
+ read = timeout.read
+ write = timeout.write
+ request = timeout.request
+ }
+
+ /**
+ * The maximum time allowed to establish a connection with a host.
+ *
+ * A value of [Duration.ZERO] means there's no timeout.
+ *
+ * Defaults to `Duration.ofMinutes(1)`.
+ */
+ fun connect(connect: Duration?) = apply { this.connect = connect }
+
+ /** Alias for calling [Builder.connect] with `connect.orElse(null)`. */
+ fun connect(connect: Optional) = connect(connect.getOrNull())
+
+ /**
+ * The maximum time allowed between two data packets when waiting for the server’s response.
+ *
+ * A value of [Duration.ZERO] means there's no timeout.
+ *
+ * Defaults to `request()`.
+ */
+ fun read(read: Duration?) = apply { this.read = read }
+
+ /** Alias for calling [Builder.read] with `read.orElse(null)`. */
+ fun read(read: Optional) = read(read.getOrNull())
+
+ /**
+ * The maximum time allowed between two data packets when sending the request to the server.
+ *
+ * A value of [Duration.ZERO] means there's no timeout.
+ *
+ * Defaults to `request()`.
+ */
+ fun write(write: Duration?) = apply { this.write = write }
+
+ /** Alias for calling [Builder.write] with `write.orElse(null)`. */
+ fun write(write: Optional) = write(write.getOrNull())
+
+ /**
+ * The maximum time allowed for a complete HTTP call, not including retries.
+ *
+ * This includes resolving DNS, connecting, writing the request body, server processing, as
+ * well as reading the response body.
+ *
+ * A value of [Duration.ZERO] means there's no timeout.
+ *
+ * Defaults to `Duration.ofMinutes(1)`.
+ */
+ fun request(request: Duration?) = apply { this.request = request }
+
+ /** Alias for calling [Builder.request] with `request.orElse(null)`. */
+ fun request(request: Optional) = request(request.getOrNull())
+
+ /**
+ * Returns an immutable instance of [Timeout].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ */
+ fun build(): Timeout = Timeout(connect, read, write, request)
+ }
+
+ @JvmSynthetic
+ internal fun assign(target: Timeout): Timeout =
+ target
+ .toBuilder()
+ .apply {
+ connect?.let(this::connect)
+ read?.let(this::read)
+ write?.let(this::write)
+ request?.let(this::request)
+ }
+ .build()
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Timeout &&
+ connect == other.connect &&
+ read == other.read &&
+ write == other.write &&
+ request == other.request
+ }
+
+ override fun hashCode(): Int = Objects.hash(connect, read, write, request)
+
+ override fun toString() =
+ "Timeout{connect=$connect, read=$read, write=$write, request=$request}"
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/Utils.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/Utils.kt
new file mode 100644
index 00000000..cac76471
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/Utils.kt
@@ -0,0 +1,115 @@
+@file:JvmName("Utils")
+
+package com.courier.api.core
+
+import com.courier.api.errors.CourierInvalidDataException
+import java.util.Collections
+import java.util.SortedMap
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.locks.Lock
+
+@JvmSynthetic
+internal fun T?.getOrThrow(name: String): T =
+ this ?: throw CourierInvalidDataException("`${name}` is not present")
+
+@JvmSynthetic
+internal fun List.toImmutable(): List =
+ if (isEmpty()) Collections.emptyList() else Collections.unmodifiableList(toList())
+
+@JvmSynthetic
+internal fun Map.toImmutable(): Map =
+ if (isEmpty()) immutableEmptyMap() else Collections.unmodifiableMap(toMap())
+
+@JvmSynthetic internal fun immutableEmptyMap(): Map = Collections.emptyMap()
+
+@JvmSynthetic
+internal fun , V> SortedMap.toImmutable(): SortedMap =
+ if (isEmpty()) Collections.emptySortedMap()
+ else Collections.unmodifiableSortedMap(toSortedMap(comparator()))
+
+/**
+ * Returns all elements that yield the largest value for the given function, or an empty list if
+ * there are zero elements.
+ *
+ * This is similar to [Sequence.maxByOrNull] except it returns _all_ elements that yield the largest
+ * value; not just the first one.
+ */
+@JvmSynthetic
+internal fun > Sequence.allMaxBy(selector: (T) -> R): List {
+ var maxValue: R? = null
+ val maxElements = mutableListOf()
+
+ val iterator = iterator()
+ while (iterator.hasNext()) {
+ val element = iterator.next()
+ val value = selector(element)
+ if (maxValue == null || value > maxValue) {
+ maxValue = value
+ maxElements.clear()
+ maxElements.add(element)
+ } else if (value == maxValue) {
+ maxElements.add(element)
+ }
+ }
+
+ return maxElements
+}
+
+/**
+ * Returns whether [this] is equal to [other].
+ *
+ * This differs from [Object.equals] because it also deeply equates arrays based on their contents,
+ * even when there are arrays directly nested within other arrays.
+ */
+@JvmSynthetic
+internal infix fun Any?.contentEquals(other: Any?): Boolean =
+ arrayOf(this).contentDeepEquals(arrayOf(other))
+
+/**
+ * Returns a hash of the given sequence of [values].
+ *
+ * This differs from [java.util.Objects.hash] because it also deeply hashes arrays based on their
+ * contents, even when there are arrays directly nested within other arrays.
+ */
+@JvmSynthetic internal fun contentHash(vararg values: Any?): Int = values.contentDeepHashCode()
+
+/**
+ * Returns a [String] representation of [this].
+ *
+ * This differs from [Object.toString] because it also deeply stringifies arrays based on their
+ * contents, even when there are arrays directly nested within other arrays.
+ */
+@JvmSynthetic
+internal fun Any?.contentToString(): String {
+ var string = arrayOf(this).contentDeepToString()
+ if (string.startsWith('[')) {
+ string = string.substring(1)
+ }
+ if (string.endsWith(']')) {
+ string = string.substring(0, string.length - 1)
+ }
+ return string
+}
+
+internal interface Enum
+
+/**
+ * Executes the given [action] while holding the lock, returning a [CompletableFuture] with the
+ * result.
+ *
+ * @param action The asynchronous action to execute while holding the lock
+ * @return A [CompletableFuture] that completes with the result of the action
+ */
+@JvmSynthetic
+internal fun Lock.withLockAsync(action: () -> CompletableFuture): CompletableFuture {
+ lock()
+ val future =
+ try {
+ action()
+ } catch (e: Throwable) {
+ unlock()
+ throw e
+ }
+ future.whenComplete { _, _ -> unlock() }
+ return future
+}
diff --git a/courier-java-core/src/main/kotlin/com/courier/api/core/Values.kt b/courier-java-core/src/main/kotlin/com/courier/api/core/Values.kt
new file mode 100644
index 00000000..4017bb76
--- /dev/null
+++ b/courier-java-core/src/main/kotlin/com/courier/api/core/Values.kt
@@ -0,0 +1,723 @@
+package com.courier.api.core
+
+import com.courier.api.errors.CourierInvalidDataException
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside
+import com.fasterxml.jackson.annotation.JsonCreator
+import com.fasterxml.jackson.annotation.JsonInclude
+import com.fasterxml.jackson.core.JsonGenerator
+import com.fasterxml.jackson.core.ObjectCodec
+import com.fasterxml.jackson.core.type.TypeReference
+import com.fasterxml.jackson.databind.BeanProperty
+import com.fasterxml.jackson.databind.DeserializationContext
+import com.fasterxml.jackson.databind.JavaType
+import com.fasterxml.jackson.databind.JsonDeserializer
+import com.fasterxml.jackson.databind.JsonNode
+import com.fasterxml.jackson.databind.SerializerProvider
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize
+import com.fasterxml.jackson.databind.annotation.JsonSerialize
+import com.fasterxml.jackson.databind.node.JsonNodeType.ARRAY
+import com.fasterxml.jackson.databind.node.JsonNodeType.BINARY
+import com.fasterxml.jackson.databind.node.JsonNodeType.BOOLEAN
+import com.fasterxml.jackson.databind.node.JsonNodeType.MISSING
+import com.fasterxml.jackson.databind.node.JsonNodeType.NULL
+import com.fasterxml.jackson.databind.node.JsonNodeType.NUMBER
+import com.fasterxml.jackson.databind.node.JsonNodeType.OBJECT
+import com.fasterxml.jackson.databind.node.JsonNodeType.POJO
+import com.fasterxml.jackson.databind.node.JsonNodeType.STRING
+import com.fasterxml.jackson.databind.ser.std.NullSerializer
+import java.io.InputStream
+import java.util.Objects
+import java.util.Optional
+
+/**
+ * A class representing a serializable JSON field.
+ *
+ * It can either be a [KnownValue] value of type [T], matching the type the SDK expects, or an
+ * arbitrary JSON value that bypasses the type system (via [JsonValue]).
+ */
+@JsonDeserialize(using = JsonField.Deserializer::class)
+sealed class JsonField {
+
+ /**
+ * Returns whether this field is missing, which means it will be omitted from the serialized
+ * JSON entirely.
+ */
+ fun isMissing(): Boolean = this is JsonMissing
+
+ /** Whether this field is explicitly set to `null`. */
+ fun isNull(): Boolean = this is JsonNull
+
+ /**
+ * Returns an [Optional] containing this field's "known" value, meaning it matches the type the
+ * SDK expects, or an empty [Optional] if this field contains an arbitrary [JsonValue].
+ *
+ * This is the opposite of [asUnknown].
+ */
+ fun asKnown():
+ Optional<
+ // Safe because `Optional` is effectively covariant, but Kotlin doesn't know that.
+ @UnsafeVariance
+ T
+ > = Optional.ofNullable((this as? KnownValue)?.value)
+
+ /**
+ * Returns an [Optional] containing this field's arbitrary [JsonValue], meaning it mismatches
+ * the type the SDK expects, or an empty [Optional] if this field contains a "known" value.
+ *
+ * This is the opposite of [asKnown].
+ */
+ fun asUnknown(): Optional = Optional.ofNullable(this as? JsonValue)
+
+ /**
+ * Returns an [Optional] containing this field's boolean value, or an empty [Optional] if it
+ * doesn't contain a boolean.
+ *
+ * This method checks for both a [KnownValue] containing a boolean and for [JsonBoolean].
+ */
+ fun asBoolean(): Optional =
+ when (this) {
+ is JsonBoolean -> Optional.of(value)
+ is KnownValue -> Optional.ofNullable(value as? Boolean)
+ else -> Optional.empty()
+ }
+
+ /**
+ * Returns an [Optional] containing this field's numerical value, or an empty [Optional] if it
+ * doesn't contain a number.
+ *
+ * This method checks for both a [KnownValue] containing a number and for [JsonNumber].
+ */
+ fun asNumber(): Optional =
+ when (this) {
+ is JsonNumber -> Optional.of(value)
+ is KnownValue -> Optional.ofNullable(value as? Number)
+ else -> Optional.empty()
+ }
+
+ /**
+ * Returns an [Optional] containing this field's string value, or an empty [Optional] if it
+ * doesn't contain a string.
+ *
+ * This method checks for both a [KnownValue] containing a string and for [JsonString].
+ */
+ fun asString(): Optional =
+ when (this) {
+ is JsonString -> Optional.of(value)
+ is KnownValue -> Optional.ofNullable(value as? String)
+ else -> Optional.empty()
+ }
+
+ fun asStringOrThrow(): String =
+ asString().orElseThrow { CourierInvalidDataException("Value is not a string") }
+
+ /**
+ * Returns an [Optional] containing this field's list value, or an empty [Optional] if it
+ * doesn't contain a list.
+ *
+ * This method checks for both a [KnownValue] containing a list and for [JsonArray].
+ */
+ fun asArray(): Optional> =
+ when (this) {
+ is JsonArray -> Optional.of(values)
+ is KnownValue ->
+ Optional.ofNullable(
+ (value as? List<*>)?.map {
+ try {
+ JsonValue.from(it)
+ } catch (e: IllegalArgumentException) {
+ // The known value is a list, but not all values are convertible to
+ // `JsonValue`.
+ return Optional.empty()
+ }
+ }
+ )
+ else -> Optional.empty()
+ }
+
+ /**
+ * Returns an [Optional] containing this field's map value, or an empty [Optional] if it doesn't
+ * contain a map.
+ *
+ * This method checks for both a [KnownValue] containing a map and for [JsonObject].
+ */
+ fun asObject(): Optional