From 3fe56ccad1fcdce5235c1ef4e3c2613879384d59 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:44:07 +0000 Subject: [PATCH 1/4] feat: spec: reorder API reference sections to match the Studio nav (#180) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to #179, rebased onto the Broadcasts merge (#170). Three changes to `specs/openapi.yml`: 1. **Reorders the sections** so the API reference reads in the same order as the Studio left nav — Content (Templates, Brands, Routing) → Orchestration (Journeys, Broadcasts) → Directory (Users, Tenants, Audiences, Lists) → Platform (Providers, Preferences) — with Send first and everything that has no nav home below. 2. **Declares the missing `Broadcasts` tag.** #170 added 11 Broadcasts operations but no entry in the top-level `tags:` array, so they were rendering as an undeclared group at the end of the sidebar, and the paths themselves sat inside the Templates section. They now have their own section, in the Studio nav's position right after Journeys. 3. **Renames `Profiles` → `User Profiles`**, matching the endpoints under it and the "user profile" language used everywhere else in the docs. Authentication moves off the top to the bottom: it is one endpoint that only client-side SDKs call, so it was crowding out Send. New order: Send · Templates · Brands · Routing Strategies · Journeys · Broadcasts · User Profiles · Tenants · Audiences · Lists · Providers · Preference Topics · User Preferences then, below the fold: Messages · Device Tokens · Tenant Memberships · Tenant Templates · Automations · Digests · Translations · Inbox · Track Events · Audit Events · Authentication Verified mechanical: parsing the spec before and after shows 85 paths and 147 operations in both, zero operation-body differences, and the only semantic changes are the `Profiles` → `User Profiles` tag on the 8 `/profiles/*` operations and the added `Broadcasts` tag declaration. `components:`, `servers:`, `info:`, and `security:` are unchanged, as are all 23 pre-existing tag descriptions. Every tag an operation carries is now declared, and every declared tag is used. No SDK surface is affected — Stainless resources come from `stainless.yml`, which this PR does not touch. Renaming the section changes its API reference slugs, so the docs side needs `/api-reference/profiles/*` → `/api-reference/user-profiles/*` redirects. Co-authored-by: Claude Opus 5 (1M context) --- .stats.yml | 4 ++-- .../src/main/kotlin/com/courier/client/CourierClient.kt | 8 ++++++++ .../main/kotlin/com/courier/client/CourierClientAsync.kt | 8 ++++++++ .../kotlin/com/courier/client/CourierClientAsyncImpl.kt | 8 ++++++++ .../main/kotlin/com/courier/client/CourierClientImpl.kt | 8 ++++++++ .../com/courier/services/async/BroadcastServiceAsync.kt | 4 ++++ .../courier/services/async/BroadcastServiceAsyncImpl.kt | 4 ++++ .../com/courier/services/blocking/BroadcastService.kt | 4 ++++ .../com/courier/services/blocking/BroadcastServiceImpl.kt | 4 ++++ 9 files changed, 50 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 29ea7c7..a3e38b1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 147 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-ca32540df5bca42c8113de4004e7751b74bb440e3d73267e7cbad84dd3c3e82a.yml -openapi_spec_hash: 5576c8cf8e5be1f250b5dd1eb6d30571 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-8d00597aee6759fa5829bdf61637a9d5f6abf7b4826cb2c7b8af491771dca0e9.yml +openapi_spec_hash: 1766885553f6733706f8a807b1e8c31b config_hash: c6cefb51165221f01d442a42ac4a13b9 diff --git a/courier-java-core/src/main/kotlin/com/courier/client/CourierClient.kt b/courier-java-core/src/main/kotlin/com/courier/client/CourierClient.kt index f47f046..ee9918f 100644 --- a/courier-java-core/src/main/kotlin/com/courier/client/CourierClient.kt +++ b/courier-java-core/src/main/kotlin/com/courier/client/CourierClient.kt @@ -97,6 +97,10 @@ interface CourierClient { */ fun journeys(): JourneyService + /** + * Create a one-off send to a list or audience, author its content, then send it immediately or + * schedule it for later. + */ fun broadcasts(): BroadcastService /** Manage the logos, colors, and layout that give the templates you send a consistent look. */ @@ -219,6 +223,10 @@ interface CourierClient { */ fun journeys(): JourneyService.WithRawResponse + /** + * Create a one-off send to a list or audience, author its content, then send it immediately + * or schedule it for later. + */ fun broadcasts(): BroadcastService.WithRawResponse /** diff --git a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsync.kt b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsync.kt index b1fe4a0..ec52269 100644 --- a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsync.kt +++ b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsync.kt @@ -97,6 +97,10 @@ interface CourierClientAsync { */ fun journeys(): JourneyServiceAsync + /** + * Create a one-off send to a list or audience, author its content, then send it immediately or + * schedule it for later. + */ fun broadcasts(): BroadcastServiceAsync /** Manage the logos, colors, and layout that give the templates you send a consistent look. */ @@ -223,6 +227,10 @@ interface CourierClientAsync { */ fun journeys(): JourneyServiceAsync.WithRawResponse + /** + * Create a one-off send to a list or audience, author its content, then send it immediately + * or schedule it for later. + */ fun broadcasts(): BroadcastServiceAsync.WithRawResponse /** diff --git a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsyncImpl.kt b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsyncImpl.kt index 8b34654..0bbf8a1 100644 --- a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsyncImpl.kt +++ b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsyncImpl.kt @@ -188,6 +188,10 @@ class CourierClientAsyncImpl(private val clientOptions: ClientOptions) : Courier */ override fun journeys(): JourneyServiceAsync = journeys + /** + * Create a one-off send to a list or audience, author its content, then send it immediately or + * schedule it for later. + */ override fun broadcasts(): BroadcastServiceAsync = broadcasts /** Manage the logos, colors, and layout that give the templates you send a consistent look. */ @@ -387,6 +391,10 @@ class CourierClientAsyncImpl(private val clientOptions: ClientOptions) : Courier */ override fun journeys(): JourneyServiceAsync.WithRawResponse = journeys + /** + * Create a one-off send to a list or audience, author its content, then send it immediately + * or schedule it for later. + */ override fun broadcasts(): BroadcastServiceAsync.WithRawResponse = broadcasts /** diff --git a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientImpl.kt b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientImpl.kt index 1594a81..07b7e4e 100644 --- a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientImpl.kt +++ b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientImpl.kt @@ -170,6 +170,10 @@ class CourierClientImpl(private val clientOptions: ClientOptions) : CourierClien */ override fun journeys(): JourneyService = journeys + /** + * Create a one-off send to a list or audience, author its content, then send it immediately or + * schedule it for later. + */ override fun broadcasts(): BroadcastService = broadcasts /** Manage the logos, colors, and layout that give the templates you send a consistent look. */ @@ -369,6 +373,10 @@ class CourierClientImpl(private val clientOptions: ClientOptions) : CourierClien */ override fun journeys(): JourneyService.WithRawResponse = journeys + /** + * Create a one-off send to a list or audience, author its content, then send it immediately + * or schedule it for later. + */ override fun broadcasts(): BroadcastService.WithRawResponse = broadcasts /** diff --git a/courier-java-core/src/main/kotlin/com/courier/services/async/BroadcastServiceAsync.kt b/courier-java-core/src/main/kotlin/com/courier/services/async/BroadcastServiceAsync.kt index 3f32205..62e2d77 100644 --- a/courier-java-core/src/main/kotlin/com/courier/services/async/BroadcastServiceAsync.kt +++ b/courier-java-core/src/main/kotlin/com/courier/services/async/BroadcastServiceAsync.kt @@ -24,6 +24,10 @@ import com.courier.models.notifications.NotificationContentMutationResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * Create a one-off send to a list or audience, author its content, then send it immediately or + * schedule it for later. + */ interface BroadcastServiceAsync { /** diff --git a/courier-java-core/src/main/kotlin/com/courier/services/async/BroadcastServiceAsyncImpl.kt b/courier-java-core/src/main/kotlin/com/courier/services/async/BroadcastServiceAsyncImpl.kt index 0b58529..03f6b13 100644 --- a/courier-java-core/src/main/kotlin/com/courier/services/async/BroadcastServiceAsyncImpl.kt +++ b/courier-java-core/src/main/kotlin/com/courier/services/async/BroadcastServiceAsyncImpl.kt @@ -35,6 +35,10 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * Create a one-off send to a list or audience, author its content, then send it immediately or + * schedule it for later. + */ class BroadcastServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : BroadcastServiceAsync { diff --git a/courier-java-core/src/main/kotlin/com/courier/services/blocking/BroadcastService.kt b/courier-java-core/src/main/kotlin/com/courier/services/blocking/BroadcastService.kt index 5473b72..7279d93 100644 --- a/courier-java-core/src/main/kotlin/com/courier/services/blocking/BroadcastService.kt +++ b/courier-java-core/src/main/kotlin/com/courier/services/blocking/BroadcastService.kt @@ -24,6 +24,10 @@ import com.courier.models.notifications.NotificationContentMutationResponse import com.google.errorprone.annotations.MustBeClosed import java.util.function.Consumer +/** + * Create a one-off send to a list or audience, author its content, then send it immediately or + * schedule it for later. + */ interface BroadcastService { /** diff --git a/courier-java-core/src/main/kotlin/com/courier/services/blocking/BroadcastServiceImpl.kt b/courier-java-core/src/main/kotlin/com/courier/services/blocking/BroadcastServiceImpl.kt index a083327..b5db366 100644 --- a/courier-java-core/src/main/kotlin/com/courier/services/blocking/BroadcastServiceImpl.kt +++ b/courier-java-core/src/main/kotlin/com/courier/services/blocking/BroadcastServiceImpl.kt @@ -34,6 +34,10 @@ import com.courier.models.notifications.NotificationContentMutationResponse import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * Create a one-off send to a list or audience, author its content, then send it immediately or + * schedule it for later. + */ class BroadcastServiceImpl internal constructor(private val clientOptions: ClientOptions) : BroadcastService { From 07e30e0228b6de99301269f039ebba887c5dff47 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 17:24:18 +0000 Subject: [PATCH 2/4] feat: spec: remove inbox message delete/restore endpoints for now (C-19268) (#182) Reverts the public documentation of DELETE /inbox/messages/{message_id} and PUT /inbox/messages/{message_id}/restore (added in #175). The server-side delete endpoint authenticates and returns 204, but the soft-delete is not reflected in the inbox read path the SDK/clients use (deleted messages still appear in the in-app inbox). Pulling the endpoints from the public API surface + SDK generation until the read-path issue is resolved. Removes: - openapi.yml: both paths + the Inbox tag (only used by these two operations) - stainless.yml: the inbox.messages resource (delete + restore) Co-authored-by: Mike Miller Co-authored-by: Claude Opus 4.8 --- .stats.yml | 8 +- .../com/courier/client/CourierClient.kt | 5 - .../com/courier/client/CourierClientAsync.kt | 5 - .../courier/client/CourierClientAsyncImpl.kt | 14 -- .../com/courier/client/CourierClientImpl.kt | 12 - .../inbox/messages/MessageDeleteParams.kt | 232 ------------------ .../inbox/messages/MessageRestoreParams.kt | 219 ----------------- .../services/async/InboxServiceAsync.kt | 41 ---- .../services/async/InboxServiceAsyncImpl.kt | 44 ---- .../async/inbox/MessageServiceAsync.kt | 164 ------------- .../async/inbox/MessageServiceAsyncImpl.kt | 118 --------- .../courier/services/blocking/InboxService.kt | 39 --- .../services/blocking/InboxServiceImpl.kt | 44 ---- .../services/blocking/inbox/MessageService.kt | 152 ------------ .../blocking/inbox/MessageServiceImpl.kt | 107 -------- .../inbox/messages/MessageDeleteParamsTest.kt | 23 -- .../messages/MessageRestoreParamsTest.kt | 44 ---- .../async/inbox/MessageServiceAsyncTest.kt | 40 --- .../blocking/inbox/MessageServiceTest.kt | 35 --- .../proguard/ProGuardCompatibilityTest.kt | 1 - 20 files changed, 4 insertions(+), 1343 deletions(-) delete mode 100644 courier-java-core/src/main/kotlin/com/courier/models/inbox/messages/MessageDeleteParams.kt delete mode 100644 courier-java-core/src/main/kotlin/com/courier/models/inbox/messages/MessageRestoreParams.kt delete mode 100644 courier-java-core/src/main/kotlin/com/courier/services/async/InboxServiceAsync.kt delete mode 100644 courier-java-core/src/main/kotlin/com/courier/services/async/InboxServiceAsyncImpl.kt delete mode 100644 courier-java-core/src/main/kotlin/com/courier/services/async/inbox/MessageServiceAsync.kt delete mode 100644 courier-java-core/src/main/kotlin/com/courier/services/async/inbox/MessageServiceAsyncImpl.kt delete mode 100644 courier-java-core/src/main/kotlin/com/courier/services/blocking/InboxService.kt delete mode 100644 courier-java-core/src/main/kotlin/com/courier/services/blocking/InboxServiceImpl.kt delete mode 100644 courier-java-core/src/main/kotlin/com/courier/services/blocking/inbox/MessageService.kt delete mode 100644 courier-java-core/src/main/kotlin/com/courier/services/blocking/inbox/MessageServiceImpl.kt delete mode 100644 courier-java-core/src/test/kotlin/com/courier/models/inbox/messages/MessageDeleteParamsTest.kt delete mode 100644 courier-java-core/src/test/kotlin/com/courier/models/inbox/messages/MessageRestoreParamsTest.kt delete mode 100644 courier-java-core/src/test/kotlin/com/courier/services/async/inbox/MessageServiceAsyncTest.kt delete mode 100644 courier-java-core/src/test/kotlin/com/courier/services/blocking/inbox/MessageServiceTest.kt diff --git a/.stats.yml b/.stats.yml index a3e38b1..06502c4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 147 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-8d00597aee6759fa5829bdf61637a9d5f6abf7b4826cb2c7b8af491771dca0e9.yml -openapi_spec_hash: 1766885553f6733706f8a807b1e8c31b -config_hash: c6cefb51165221f01d442a42ac4a13b9 +configured_endpoints: 145 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-b4485f5c4897c26d52a46aeb39b8a22415bcd529b0ad326fd43a30d7fadf1376.yml +openapi_spec_hash: db619c8991994dc8016fc4327f6917a2 +config_hash: 3eb0070d128aef7a6da16173f7050177 diff --git a/courier-java-core/src/main/kotlin/com/courier/client/CourierClient.kt b/courier-java-core/src/main/kotlin/com/courier/client/CourierClient.kt index ee9918f..9505cef 100644 --- a/courier-java-core/src/main/kotlin/com/courier/client/CourierClient.kt +++ b/courier-java-core/src/main/kotlin/com/courier/client/CourierClient.kt @@ -11,7 +11,6 @@ import com.courier.services.blocking.BrandService import com.courier.services.blocking.BroadcastService import com.courier.services.blocking.DigestService import com.courier.services.blocking.InboundService -import com.courier.services.blocking.InboxService import com.courier.services.blocking.JourneyService import com.courier.services.blocking.ListService import com.courier.services.blocking.MessageService @@ -117,8 +116,6 @@ interface CourierClient { */ fun lists(): ListService - fun inbox(): InboxService - /** * Look up the messages Courier has accepted, inspect their delivery history and rendered * output, and cancel, resend, or archive them. @@ -245,8 +242,6 @@ interface CourierClient { */ fun lists(): ListService.WithRawResponse - fun inbox(): InboxService.WithRawResponse - /** * Look up the messages Courier has accepted, inspect their delivery history and rendered * output, and cancel, resend, or archive them. diff --git a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsync.kt b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsync.kt index ec52269..835c15e 100644 --- a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsync.kt +++ b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsync.kt @@ -11,7 +11,6 @@ import com.courier.services.async.BrandServiceAsync import com.courier.services.async.BroadcastServiceAsync import com.courier.services.async.DigestServiceAsync import com.courier.services.async.InboundServiceAsync -import com.courier.services.async.InboxServiceAsync import com.courier.services.async.JourneyServiceAsync import com.courier.services.async.ListServiceAsync import com.courier.services.async.MessageServiceAsync @@ -117,8 +116,6 @@ interface CourierClientAsync { */ fun lists(): ListServiceAsync - fun inbox(): InboxServiceAsync - /** * Look up the messages Courier has accepted, inspect their delivery history and rendered * output, and cancel, resend, or archive them. @@ -249,8 +246,6 @@ interface CourierClientAsync { */ fun lists(): ListServiceAsync.WithRawResponse - fun inbox(): InboxServiceAsync.WithRawResponse - /** * Look up the messages Courier has accepted, inspect their delivery history and rendered * output, and cancel, resend, or archive them. diff --git a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsyncImpl.kt b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsyncImpl.kt index 0bbf8a1..ed3d572 100644 --- a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsyncImpl.kt +++ b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientAsyncImpl.kt @@ -20,8 +20,6 @@ import com.courier.services.async.DigestServiceAsync import com.courier.services.async.DigestServiceAsyncImpl import com.courier.services.async.InboundServiceAsync import com.courier.services.async.InboundServiceAsyncImpl -import com.courier.services.async.InboxServiceAsync -import com.courier.services.async.InboxServiceAsyncImpl import com.courier.services.async.JourneyServiceAsync import com.courier.services.async.JourneyServiceAsyncImpl import com.courier.services.async.ListServiceAsync @@ -109,10 +107,6 @@ class CourierClientAsyncImpl(private val clientOptions: ClientOptions) : Courier private val lists: ListServiceAsync by lazy { ListServiceAsyncImpl(clientOptionsWithUserAgent) } - private val inbox: InboxServiceAsync by lazy { - InboxServiceAsyncImpl(clientOptionsWithUserAgent) - } - private val messages: MessageServiceAsync by lazy { MessageServiceAsyncImpl(clientOptionsWithUserAgent) } @@ -208,8 +202,6 @@ class CourierClientAsyncImpl(private val clientOptions: ClientOptions) : Courier */ override fun lists(): ListServiceAsync = lists - override fun inbox(): InboxServiceAsync = inbox - /** * Look up the messages Courier has accepted, inspect their delivery history and rendered * output, and cancel, resend, or archive them. @@ -308,10 +300,6 @@ class CourierClientAsyncImpl(private val clientOptions: ClientOptions) : Courier ListServiceAsyncImpl.WithRawResponseImpl(clientOptions) } - private val inbox: InboxServiceAsync.WithRawResponse by lazy { - InboxServiceAsyncImpl.WithRawResponseImpl(clientOptions) - } - private val messages: MessageServiceAsync.WithRawResponse by lazy { MessageServiceAsyncImpl.WithRawResponseImpl(clientOptions) } @@ -413,8 +401,6 @@ class CourierClientAsyncImpl(private val clientOptions: ClientOptions) : Courier */ override fun lists(): ListServiceAsync.WithRawResponse = lists - override fun inbox(): InboxServiceAsync.WithRawResponse = inbox - /** * Look up the messages Courier has accepted, inspect their delivery history and rendered * output, and cancel, resend, or archive them. diff --git a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientImpl.kt b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientImpl.kt index 07b7e4e..497c779 100644 --- a/courier-java-core/src/main/kotlin/com/courier/client/CourierClientImpl.kt +++ b/courier-java-core/src/main/kotlin/com/courier/client/CourierClientImpl.kt @@ -20,8 +20,6 @@ import com.courier.services.blocking.DigestService import com.courier.services.blocking.DigestServiceImpl import com.courier.services.blocking.InboundService import com.courier.services.blocking.InboundServiceImpl -import com.courier.services.blocking.InboxService -import com.courier.services.blocking.InboxServiceImpl import com.courier.services.blocking.JourneyService import com.courier.services.blocking.JourneyServiceImpl import com.courier.services.blocking.ListService @@ -101,8 +99,6 @@ class CourierClientImpl(private val clientOptions: ClientOptions) : CourierClien private val lists: ListService by lazy { ListServiceImpl(clientOptionsWithUserAgent) } - private val inbox: InboxService by lazy { InboxServiceImpl(clientOptionsWithUserAgent) } - private val messages: MessageService by lazy { MessageServiceImpl(clientOptionsWithUserAgent) } private val requests: RequestService by lazy { RequestServiceImpl(clientOptionsWithUserAgent) } @@ -190,8 +186,6 @@ class CourierClientImpl(private val clientOptions: ClientOptions) : CourierClien */ override fun lists(): ListService = lists - override fun inbox(): InboxService = inbox - /** * Look up the messages Courier has accepted, inspect their delivery history and rendered * output, and cancel, resend, or archive them. @@ -290,10 +284,6 @@ class CourierClientImpl(private val clientOptions: ClientOptions) : CourierClien ListServiceImpl.WithRawResponseImpl(clientOptions) } - private val inbox: InboxService.WithRawResponse by lazy { - InboxServiceImpl.WithRawResponseImpl(clientOptions) - } - private val messages: MessageService.WithRawResponse by lazy { MessageServiceImpl.WithRawResponseImpl(clientOptions) } @@ -395,8 +385,6 @@ class CourierClientImpl(private val clientOptions: ClientOptions) : CourierClien */ override fun lists(): ListService.WithRawResponse = lists - override fun inbox(): InboxService.WithRawResponse = inbox - /** * Look up the messages Courier has accepted, inspect their delivery history and rendered * output, and cancel, resend, or archive them. diff --git a/courier-java-core/src/main/kotlin/com/courier/models/inbox/messages/MessageDeleteParams.kt b/courier-java-core/src/main/kotlin/com/courier/models/inbox/messages/MessageDeleteParams.kt deleted file mode 100644 index 1f4c457..0000000 --- a/courier-java-core/src/main/kotlin/com/courier/models/inbox/messages/MessageDeleteParams.kt +++ /dev/null @@ -1,232 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.models.inbox.messages - -import com.courier.core.JsonValue -import com.courier.core.Params -import com.courier.core.http.Headers -import com.courier.core.http.QueryParams -import com.courier.core.toImmutable -import java.util.Objects -import java.util.Optional -import kotlin.jvm.optionals.getOrNull - -/** - * Delete a user's inbox message. The message is removed from every inbox read (it stops appearing - * in the recipient's Inbox); it can be restored. - */ -class MessageDeleteParams -private constructor( - private val messageId: String?, - private val additionalHeaders: Headers, - private val additionalQueryParams: QueryParams, - private val additionalBodyProperties: Map, -) : Params { - - fun messageId(): Optional = Optional.ofNullable(messageId) - - /** Additional body properties to send with the request. */ - fun _additionalBodyProperties(): Map = additionalBodyProperties - - /** Additional headers to send with the request. */ - fun _additionalHeaders(): Headers = additionalHeaders - - /** Additional query param to send with the request. */ - fun _additionalQueryParams(): QueryParams = additionalQueryParams - - fun toBuilder() = Builder().from(this) - - companion object { - - @JvmStatic fun none(): MessageDeleteParams = builder().build() - - /** Returns a mutable builder for constructing an instance of [MessageDeleteParams]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [MessageDeleteParams]. */ - class Builder internal constructor() { - - private var messageId: String? = null - private var additionalHeaders: Headers.Builder = Headers.builder() - private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - private var additionalBodyProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(messageDeleteParams: MessageDeleteParams) = apply { - messageId = messageDeleteParams.messageId - additionalHeaders = messageDeleteParams.additionalHeaders.toBuilder() - additionalQueryParams = messageDeleteParams.additionalQueryParams.toBuilder() - additionalBodyProperties = messageDeleteParams.additionalBodyProperties.toMutableMap() - } - - fun messageId(messageId: String?) = apply { this.messageId = messageId } - - /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ - fun messageId(messageId: Optional) = messageId(messageId.getOrNull()) - - fun additionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun putAdditionalHeader(name: String, value: String) = apply { - additionalHeaders.put(name, value) - } - - fun putAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.put(name, values) - } - - fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun replaceAdditionalHeaders(name: String, value: String) = apply { - additionalHeaders.replace(name, value) - } - - fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.replace(name, values) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - - fun removeAllAdditionalHeaders(names: Set) = apply { - additionalHeaders.removeAll(names) - } - - fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun putAdditionalQueryParam(key: String, value: String) = apply { - additionalQueryParams.put(key, value) - } - - fun putAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.put(key, values) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun replaceAdditionalQueryParams(key: String, value: String) = apply { - additionalQueryParams.replace(key, value) - } - - fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.replace(key, values) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - - fun removeAllAdditionalQueryParams(keys: Set) = apply { - additionalQueryParams.removeAll(keys) - } - - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - putAllAdditionalBodyProperties(additionalBodyProperties) - } - - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - additionalBodyProperties.put(key, value) - } - - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } - - fun removeAdditionalBodyProperty(key: String) = apply { - additionalBodyProperties.remove(key) - } - - fun removeAllAdditionalBodyProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalBodyProperty) - } - - /** - * Returns an immutable instance of [MessageDeleteParams]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): MessageDeleteParams = - MessageDeleteParams( - messageId, - additionalHeaders.build(), - additionalQueryParams.build(), - additionalBodyProperties.toImmutable(), - ) - } - - fun _body(): Optional> = - Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) - - fun _pathParam(index: Int): String = - when (index) { - 0 -> messageId ?: "" - else -> "" - } - - override fun _headers(): Headers = additionalHeaders - - override fun _queryParams(): QueryParams = additionalQueryParams - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is MessageDeleteParams && - messageId == other.messageId && - additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams && - additionalBodyProperties == other.additionalBodyProperties - } - - override fun hashCode(): Int = - Objects.hash(messageId, additionalHeaders, additionalQueryParams, additionalBodyProperties) - - override fun toString() = - "MessageDeleteParams{messageId=$messageId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" -} diff --git a/courier-java-core/src/main/kotlin/com/courier/models/inbox/messages/MessageRestoreParams.kt b/courier-java-core/src/main/kotlin/com/courier/models/inbox/messages/MessageRestoreParams.kt deleted file mode 100644 index 4b2608d..0000000 --- a/courier-java-core/src/main/kotlin/com/courier/models/inbox/messages/MessageRestoreParams.kt +++ /dev/null @@ -1,219 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.models.inbox.messages - -import com.courier.core.JsonValue -import com.courier.core.Params -import com.courier.core.checkRequired -import com.courier.core.http.Headers -import com.courier.core.http.QueryParams -import java.util.Objects -import java.util.Optional -import kotlin.jvm.optionals.getOrNull - -/** Restore a previously deleted inbox message. */ -class MessageRestoreParams -private constructor( - private val messageId: String?, - private val body: JsonValue, - private val additionalHeaders: Headers, - private val additionalQueryParams: QueryParams, -) : Params { - - fun messageId(): Optional = Optional.ofNullable(messageId) - - fun body(): JsonValue = body - - /** Additional headers to send with the request. */ - fun _additionalHeaders(): Headers = additionalHeaders - - /** Additional query param to send with the request. */ - fun _additionalQueryParams(): QueryParams = additionalQueryParams - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [MessageRestoreParams]. - * - * The following fields are required: - * ```java - * .body() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [MessageRestoreParams]. */ - class Builder internal constructor() { - - private var messageId: String? = null - private var body: JsonValue? = null - private var additionalHeaders: Headers.Builder = Headers.builder() - private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - - @JvmSynthetic - internal fun from(messageRestoreParams: MessageRestoreParams) = apply { - messageId = messageRestoreParams.messageId - body = messageRestoreParams.body - additionalHeaders = messageRestoreParams.additionalHeaders.toBuilder() - additionalQueryParams = messageRestoreParams.additionalQueryParams.toBuilder() - } - - fun messageId(messageId: String?) = apply { this.messageId = messageId } - - /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ - fun messageId(messageId: Optional) = messageId(messageId.getOrNull()) - - fun body(body: JsonValue) = apply { this.body = body } - - fun additionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun putAdditionalHeader(name: String, value: String) = apply { - additionalHeaders.put(name, value) - } - - fun putAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.put(name, values) - } - - fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun replaceAdditionalHeaders(name: String, value: String) = apply { - additionalHeaders.replace(name, value) - } - - fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.replace(name, values) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - - fun removeAllAdditionalHeaders(names: Set) = apply { - additionalHeaders.removeAll(names) - } - - fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun putAdditionalQueryParam(key: String, value: String) = apply { - additionalQueryParams.put(key, value) - } - - fun putAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.put(key, values) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun replaceAdditionalQueryParams(key: String, value: String) = apply { - additionalQueryParams.replace(key, value) - } - - fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.replace(key, values) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - - fun removeAllAdditionalQueryParams(keys: Set) = apply { - additionalQueryParams.removeAll(keys) - } - - /** - * Returns an immutable instance of [MessageRestoreParams]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .body() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): MessageRestoreParams = - MessageRestoreParams( - messageId, - checkRequired("body", body), - additionalHeaders.build(), - additionalQueryParams.build(), - ) - } - - fun _body(): JsonValue = body - - fun _pathParam(index: Int): String = - when (index) { - 0 -> messageId ?: "" - else -> "" - } - - override fun _headers(): Headers = additionalHeaders - - override fun _queryParams(): QueryParams = additionalQueryParams - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is MessageRestoreParams && - messageId == other.messageId && - body == other.body && - additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams - } - - override fun hashCode(): Int = - Objects.hash(messageId, body, additionalHeaders, additionalQueryParams) - - override fun toString() = - "MessageRestoreParams{messageId=$messageId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" -} diff --git a/courier-java-core/src/main/kotlin/com/courier/services/async/InboxServiceAsync.kt b/courier-java-core/src/main/kotlin/com/courier/services/async/InboxServiceAsync.kt deleted file mode 100644 index 2730595..0000000 --- a/courier-java-core/src/main/kotlin/com/courier/services/async/InboxServiceAsync.kt +++ /dev/null @@ -1,41 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.services.async - -import com.courier.core.ClientOptions -import com.courier.services.async.inbox.MessageServiceAsync -import java.util.function.Consumer - -interface InboxServiceAsync { - - /** - * 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): InboxServiceAsync - - /** Manage the messages in a user's in-app inbox. */ - fun messages(): MessageServiceAsync - - /** A view of [InboxServiceAsync] 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 - ): InboxServiceAsync.WithRawResponse - - /** Manage the messages in a user's in-app inbox. */ - fun messages(): MessageServiceAsync.WithRawResponse - } -} diff --git a/courier-java-core/src/main/kotlin/com/courier/services/async/InboxServiceAsyncImpl.kt b/courier-java-core/src/main/kotlin/com/courier/services/async/InboxServiceAsyncImpl.kt deleted file mode 100644 index 0ad14fa..0000000 --- a/courier-java-core/src/main/kotlin/com/courier/services/async/InboxServiceAsyncImpl.kt +++ /dev/null @@ -1,44 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.services.async - -import com.courier.core.ClientOptions -import com.courier.services.async.inbox.MessageServiceAsync -import com.courier.services.async.inbox.MessageServiceAsyncImpl -import java.util.function.Consumer - -class InboxServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : - InboxServiceAsync { - - private val withRawResponse: InboxServiceAsync.WithRawResponse by lazy { - WithRawResponseImpl(clientOptions) - } - - private val messages: MessageServiceAsync by lazy { MessageServiceAsyncImpl(clientOptions) } - - override fun withRawResponse(): InboxServiceAsync.WithRawResponse = withRawResponse - - override fun withOptions(modifier: Consumer): InboxServiceAsync = - InboxServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) - - /** Manage the messages in a user's in-app inbox. */ - override fun messages(): MessageServiceAsync = messages - - class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : - InboxServiceAsync.WithRawResponse { - - private val messages: MessageServiceAsync.WithRawResponse by lazy { - MessageServiceAsyncImpl.WithRawResponseImpl(clientOptions) - } - - override fun withOptions( - modifier: Consumer - ): InboxServiceAsync.WithRawResponse = - InboxServiceAsyncImpl.WithRawResponseImpl( - clientOptions.toBuilder().apply(modifier::accept).build() - ) - - /** Manage the messages in a user's in-app inbox. */ - override fun messages(): MessageServiceAsync.WithRawResponse = messages - } -} diff --git a/courier-java-core/src/main/kotlin/com/courier/services/async/inbox/MessageServiceAsync.kt b/courier-java-core/src/main/kotlin/com/courier/services/async/inbox/MessageServiceAsync.kt deleted file mode 100644 index 821d595..0000000 --- a/courier-java-core/src/main/kotlin/com/courier/services/async/inbox/MessageServiceAsync.kt +++ /dev/null @@ -1,164 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.services.async.inbox - -import com.courier.core.ClientOptions -import com.courier.core.RequestOptions -import com.courier.core.http.HttpResponse -import com.courier.models.inbox.messages.MessageDeleteParams -import com.courier.models.inbox.messages.MessageRestoreParams -import java.util.concurrent.CompletableFuture -import java.util.function.Consumer - -/** Manage the messages in a user's in-app inbox. */ -interface MessageServiceAsync { - - /** - * 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): MessageServiceAsync - - /** - * Delete a user's inbox message. The message is removed from every inbox read (it stops - * appearing in the recipient's Inbox); it can be restored. - */ - fun delete(messageId: String): CompletableFuture = - delete(messageId, MessageDeleteParams.none()) - - /** @see delete */ - fun delete( - messageId: String, - params: MessageDeleteParams = MessageDeleteParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - delete(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see delete */ - fun delete( - messageId: String, - params: MessageDeleteParams = MessageDeleteParams.none(), - ): CompletableFuture = delete(messageId, params, RequestOptions.none()) - - /** @see delete */ - fun delete( - params: MessageDeleteParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture - - /** @see delete */ - fun delete(params: MessageDeleteParams): CompletableFuture = - delete(params, RequestOptions.none()) - - /** @see delete */ - fun delete(messageId: String, requestOptions: RequestOptions): CompletableFuture = - delete(messageId, MessageDeleteParams.none(), requestOptions) - - /** Restore a previously deleted inbox message. */ - fun restore(messageId: String, params: MessageRestoreParams): CompletableFuture = - restore(messageId, params, RequestOptions.none()) - - /** @see restore */ - fun restore( - messageId: String, - params: MessageRestoreParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - restore(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see restore */ - fun restore(params: MessageRestoreParams): CompletableFuture = - restore(params, RequestOptions.none()) - - /** @see restore */ - fun restore( - params: MessageRestoreParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture - - /** - * A view of [MessageServiceAsync] 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 - ): MessageServiceAsync.WithRawResponse - - /** - * Returns a raw HTTP response for `delete /inbox/messages/{message_id}`, but is otherwise - * the same as [MessageServiceAsync.delete]. - */ - fun delete(messageId: String): CompletableFuture = - delete(messageId, MessageDeleteParams.none()) - - /** @see delete */ - fun delete( - messageId: String, - params: MessageDeleteParams = MessageDeleteParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - delete(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see delete */ - fun delete( - messageId: String, - params: MessageDeleteParams = MessageDeleteParams.none(), - ): CompletableFuture = delete(messageId, params, RequestOptions.none()) - - /** @see delete */ - fun delete( - params: MessageDeleteParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture - - /** @see delete */ - fun delete(params: MessageDeleteParams): CompletableFuture = - delete(params, RequestOptions.none()) - - /** @see delete */ - fun delete( - messageId: String, - requestOptions: RequestOptions, - ): CompletableFuture = - delete(messageId, MessageDeleteParams.none(), requestOptions) - - /** - * Returns a raw HTTP response for `put /inbox/messages/{message_id}/restore`, but is - * otherwise the same as [MessageServiceAsync.restore]. - */ - fun restore( - messageId: String, - params: MessageRestoreParams, - ): CompletableFuture = restore(messageId, params, RequestOptions.none()) - - /** @see restore */ - fun restore( - messageId: String, - params: MessageRestoreParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - restore(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see restore */ - fun restore(params: MessageRestoreParams): CompletableFuture = - restore(params, RequestOptions.none()) - - /** @see restore */ - fun restore( - params: MessageRestoreParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture - } -} diff --git a/courier-java-core/src/main/kotlin/com/courier/services/async/inbox/MessageServiceAsyncImpl.kt b/courier-java-core/src/main/kotlin/com/courier/services/async/inbox/MessageServiceAsyncImpl.kt deleted file mode 100644 index e15a01a..0000000 --- a/courier-java-core/src/main/kotlin/com/courier/services/async/inbox/MessageServiceAsyncImpl.kt +++ /dev/null @@ -1,118 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.services.async.inbox - -import com.courier.core.ClientOptions -import com.courier.core.RequestOptions -import com.courier.core.checkRequired -import com.courier.core.handlers.emptyHandler -import com.courier.core.handlers.errorBodyHandler -import com.courier.core.handlers.errorHandler -import com.courier.core.http.HttpMethod -import com.courier.core.http.HttpRequest -import com.courier.core.http.HttpResponse -import com.courier.core.http.HttpResponse.Handler -import com.courier.core.http.json -import com.courier.core.http.parseable -import com.courier.core.prepareAsync -import com.courier.models.inbox.messages.MessageDeleteParams -import com.courier.models.inbox.messages.MessageRestoreParams -import java.util.concurrent.CompletableFuture -import java.util.function.Consumer -import kotlin.jvm.optionals.getOrNull - -/** Manage the messages in a user's in-app inbox. */ -class MessageServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : - MessageServiceAsync { - - private val withRawResponse: MessageServiceAsync.WithRawResponse by lazy { - WithRawResponseImpl(clientOptions) - } - - override fun withRawResponse(): MessageServiceAsync.WithRawResponse = withRawResponse - - override fun withOptions(modifier: Consumer): MessageServiceAsync = - MessageServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) - - override fun delete( - params: MessageDeleteParams, - requestOptions: RequestOptions, - ): CompletableFuture = - // delete /inbox/messages/{message_id} - withRawResponse().delete(params, requestOptions).thenAccept {} - - override fun restore( - params: MessageRestoreParams, - requestOptions: RequestOptions, - ): CompletableFuture = - // put /inbox/messages/{message_id}/restore - withRawResponse().restore(params, requestOptions).thenAccept {} - - class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : - MessageServiceAsync.WithRawResponse { - - private val errorHandler: Handler = - errorHandler(errorBodyHandler(clientOptions.jsonMapper)) - - override fun withOptions( - modifier: Consumer - ): MessageServiceAsync.WithRawResponse = - MessageServiceAsyncImpl.WithRawResponseImpl( - clientOptions.toBuilder().apply(modifier::accept).build() - ) - - private val deleteHandler: Handler = emptyHandler() - - override fun delete( - params: MessageDeleteParams, - requestOptions: RequestOptions, - ): CompletableFuture { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("messageId", params.messageId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("inbox", "messages", params._pathParam(0)) - .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } - .build() - .prepareAsync(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - return request - .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } - .thenApply { response -> - errorHandler.handle(response).parseable { - response.use { deleteHandler.handle(it) } - } - } - } - - private val restoreHandler: Handler = emptyHandler() - - override fun restore( - params: MessageRestoreParams, - requestOptions: RequestOptions, - ): CompletableFuture { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("messageId", params.messageId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("inbox", "messages", params._pathParam(0), "restore") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepareAsync(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - return request - .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } - .thenApply { response -> - errorHandler.handle(response).parseable { - response.use { restoreHandler.handle(it) } - } - } - } - } -} diff --git a/courier-java-core/src/main/kotlin/com/courier/services/blocking/InboxService.kt b/courier-java-core/src/main/kotlin/com/courier/services/blocking/InboxService.kt deleted file mode 100644 index c83883b..0000000 --- a/courier-java-core/src/main/kotlin/com/courier/services/blocking/InboxService.kt +++ /dev/null @@ -1,39 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.services.blocking - -import com.courier.core.ClientOptions -import com.courier.services.blocking.inbox.MessageService -import java.util.function.Consumer - -interface InboxService { - - /** - * 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): InboxService - - /** Manage the messages in a user's in-app inbox. */ - fun messages(): MessageService - - /** A view of [InboxService] 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): InboxService.WithRawResponse - - /** Manage the messages in a user's in-app inbox. */ - fun messages(): MessageService.WithRawResponse - } -} diff --git a/courier-java-core/src/main/kotlin/com/courier/services/blocking/InboxServiceImpl.kt b/courier-java-core/src/main/kotlin/com/courier/services/blocking/InboxServiceImpl.kt deleted file mode 100644 index 670ae13..0000000 --- a/courier-java-core/src/main/kotlin/com/courier/services/blocking/InboxServiceImpl.kt +++ /dev/null @@ -1,44 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.services.blocking - -import com.courier.core.ClientOptions -import com.courier.services.blocking.inbox.MessageService -import com.courier.services.blocking.inbox.MessageServiceImpl -import java.util.function.Consumer - -class InboxServiceImpl internal constructor(private val clientOptions: ClientOptions) : - InboxService { - - private val withRawResponse: InboxService.WithRawResponse by lazy { - WithRawResponseImpl(clientOptions) - } - - private val messages: MessageService by lazy { MessageServiceImpl(clientOptions) } - - override fun withRawResponse(): InboxService.WithRawResponse = withRawResponse - - override fun withOptions(modifier: Consumer): InboxService = - InboxServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) - - /** Manage the messages in a user's in-app inbox. */ - override fun messages(): MessageService = messages - - class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : - InboxService.WithRawResponse { - - private val messages: MessageService.WithRawResponse by lazy { - MessageServiceImpl.WithRawResponseImpl(clientOptions) - } - - override fun withOptions( - modifier: Consumer - ): InboxService.WithRawResponse = - InboxServiceImpl.WithRawResponseImpl( - clientOptions.toBuilder().apply(modifier::accept).build() - ) - - /** Manage the messages in a user's in-app inbox. */ - override fun messages(): MessageService.WithRawResponse = messages - } -} diff --git a/courier-java-core/src/main/kotlin/com/courier/services/blocking/inbox/MessageService.kt b/courier-java-core/src/main/kotlin/com/courier/services/blocking/inbox/MessageService.kt deleted file mode 100644 index 607fd59..0000000 --- a/courier-java-core/src/main/kotlin/com/courier/services/blocking/inbox/MessageService.kt +++ /dev/null @@ -1,152 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.services.blocking.inbox - -import com.courier.core.ClientOptions -import com.courier.core.RequestOptions -import com.courier.core.http.HttpResponse -import com.courier.models.inbox.messages.MessageDeleteParams -import com.courier.models.inbox.messages.MessageRestoreParams -import com.google.errorprone.annotations.MustBeClosed -import java.util.function.Consumer - -/** Manage the messages in a user's in-app inbox. */ -interface MessageService { - - /** - * 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): MessageService - - /** - * Delete a user's inbox message. The message is removed from every inbox read (it stops - * appearing in the recipient's Inbox); it can be restored. - */ - fun delete(messageId: String) = delete(messageId, MessageDeleteParams.none()) - - /** @see delete */ - fun delete( - messageId: String, - params: MessageDeleteParams = MessageDeleteParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ) = delete(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see delete */ - fun delete(messageId: String, params: MessageDeleteParams = MessageDeleteParams.none()) = - delete(messageId, params, RequestOptions.none()) - - /** @see delete */ - fun delete(params: MessageDeleteParams, requestOptions: RequestOptions = RequestOptions.none()) - - /** @see delete */ - fun delete(params: MessageDeleteParams) = delete(params, RequestOptions.none()) - - /** @see delete */ - fun delete(messageId: String, requestOptions: RequestOptions) = - delete(messageId, MessageDeleteParams.none(), requestOptions) - - /** Restore a previously deleted inbox message. */ - fun restore(messageId: String, params: MessageRestoreParams) = - restore(messageId, params, RequestOptions.none()) - - /** @see restore */ - fun restore( - messageId: String, - params: MessageRestoreParams, - requestOptions: RequestOptions = RequestOptions.none(), - ) = restore(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see restore */ - fun restore(params: MessageRestoreParams) = restore(params, RequestOptions.none()) - - /** @see restore */ - fun restore( - params: MessageRestoreParams, - requestOptions: RequestOptions = RequestOptions.none(), - ) - - /** A view of [MessageService] 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): MessageService.WithRawResponse - - /** - * Returns a raw HTTP response for `delete /inbox/messages/{message_id}`, but is otherwise - * the same as [MessageService.delete]. - */ - @MustBeClosed - fun delete(messageId: String): HttpResponse = delete(messageId, MessageDeleteParams.none()) - - /** @see delete */ - @MustBeClosed - fun delete( - messageId: String, - params: MessageDeleteParams = MessageDeleteParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponse = delete(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see delete */ - @MustBeClosed - fun delete( - messageId: String, - params: MessageDeleteParams = MessageDeleteParams.none(), - ): HttpResponse = delete(messageId, params, RequestOptions.none()) - - /** @see delete */ - @MustBeClosed - fun delete( - params: MessageDeleteParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponse - - /** @see delete */ - @MustBeClosed - fun delete(params: MessageDeleteParams): HttpResponse = - delete(params, RequestOptions.none()) - - /** @see delete */ - @MustBeClosed - fun delete(messageId: String, requestOptions: RequestOptions): HttpResponse = - delete(messageId, MessageDeleteParams.none(), requestOptions) - - /** - * Returns a raw HTTP response for `put /inbox/messages/{message_id}/restore`, but is - * otherwise the same as [MessageService.restore]. - */ - @MustBeClosed - fun restore(messageId: String, params: MessageRestoreParams): HttpResponse = - restore(messageId, params, RequestOptions.none()) - - /** @see restore */ - @MustBeClosed - fun restore( - messageId: String, - params: MessageRestoreParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponse = restore(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see restore */ - @MustBeClosed - fun restore(params: MessageRestoreParams): HttpResponse = - restore(params, RequestOptions.none()) - - /** @see restore */ - @MustBeClosed - fun restore( - params: MessageRestoreParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponse - } -} diff --git a/courier-java-core/src/main/kotlin/com/courier/services/blocking/inbox/MessageServiceImpl.kt b/courier-java-core/src/main/kotlin/com/courier/services/blocking/inbox/MessageServiceImpl.kt deleted file mode 100644 index 422d822..0000000 --- a/courier-java-core/src/main/kotlin/com/courier/services/blocking/inbox/MessageServiceImpl.kt +++ /dev/null @@ -1,107 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.services.blocking.inbox - -import com.courier.core.ClientOptions -import com.courier.core.RequestOptions -import com.courier.core.checkRequired -import com.courier.core.handlers.emptyHandler -import com.courier.core.handlers.errorBodyHandler -import com.courier.core.handlers.errorHandler -import com.courier.core.http.HttpMethod -import com.courier.core.http.HttpRequest -import com.courier.core.http.HttpResponse -import com.courier.core.http.HttpResponse.Handler -import com.courier.core.http.json -import com.courier.core.http.parseable -import com.courier.core.prepare -import com.courier.models.inbox.messages.MessageDeleteParams -import com.courier.models.inbox.messages.MessageRestoreParams -import java.util.function.Consumer -import kotlin.jvm.optionals.getOrNull - -/** Manage the messages in a user's in-app inbox. */ -class MessageServiceImpl internal constructor(private val clientOptions: ClientOptions) : - MessageService { - - private val withRawResponse: MessageService.WithRawResponse by lazy { - WithRawResponseImpl(clientOptions) - } - - override fun withRawResponse(): MessageService.WithRawResponse = withRawResponse - - override fun withOptions(modifier: Consumer): MessageService = - MessageServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) - - override fun delete(params: MessageDeleteParams, requestOptions: RequestOptions) { - // delete /inbox/messages/{message_id} - withRawResponse().delete(params, requestOptions) - } - - override fun restore(params: MessageRestoreParams, requestOptions: RequestOptions) { - // put /inbox/messages/{message_id}/restore - withRawResponse().restore(params, requestOptions) - } - - class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : - MessageService.WithRawResponse { - - private val errorHandler: Handler = - errorHandler(errorBodyHandler(clientOptions.jsonMapper)) - - override fun withOptions( - modifier: Consumer - ): MessageService.WithRawResponse = - MessageServiceImpl.WithRawResponseImpl( - clientOptions.toBuilder().apply(modifier::accept).build() - ) - - private val deleteHandler: Handler = emptyHandler() - - override fun delete( - params: MessageDeleteParams, - requestOptions: RequestOptions, - ): HttpResponse { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("messageId", params.messageId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("inbox", "messages", params._pathParam(0)) - .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } - .build() - .prepare(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - val response = clientOptions.httpClient.execute(request, requestOptions) - return errorHandler.handle(response).parseable { - response.use { deleteHandler.handle(it) } - } - } - - private val restoreHandler: Handler = emptyHandler() - - override fun restore( - params: MessageRestoreParams, - requestOptions: RequestOptions, - ): HttpResponse { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("messageId", params.messageId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("inbox", "messages", params._pathParam(0), "restore") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepare(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - val response = clientOptions.httpClient.execute(request, requestOptions) - return errorHandler.handle(response).parseable { - response.use { restoreHandler.handle(it) } - } - } - } -} diff --git a/courier-java-core/src/test/kotlin/com/courier/models/inbox/messages/MessageDeleteParamsTest.kt b/courier-java-core/src/test/kotlin/com/courier/models/inbox/messages/MessageDeleteParamsTest.kt deleted file mode 100644 index 7858a6a..0000000 --- a/courier-java-core/src/test/kotlin/com/courier/models/inbox/messages/MessageDeleteParamsTest.kt +++ /dev/null @@ -1,23 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.models.inbox.messages - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class MessageDeleteParamsTest { - - @Test - fun create() { - MessageDeleteParams.builder().messageId("message_id").build() - } - - @Test - fun pathParams() { - val params = MessageDeleteParams.builder().messageId("message_id").build() - - assertThat(params._pathParam(0)).isEqualTo("message_id") - // out-of-bound path param - assertThat(params._pathParam(1)).isEqualTo("") - } -} diff --git a/courier-java-core/src/test/kotlin/com/courier/models/inbox/messages/MessageRestoreParamsTest.kt b/courier-java-core/src/test/kotlin/com/courier/models/inbox/messages/MessageRestoreParamsTest.kt deleted file mode 100644 index 3dc903d..0000000 --- a/courier-java-core/src/test/kotlin/com/courier/models/inbox/messages/MessageRestoreParamsTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.models.inbox.messages - -import com.courier.core.JsonValue -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class MessageRestoreParamsTest { - - @Test - fun create() { - MessageRestoreParams.builder() - .messageId("message_id") - .body(JsonValue.from(mapOf())) - .build() - } - - @Test - fun pathParams() { - val params = - MessageRestoreParams.builder() - .messageId("message_id") - .body(JsonValue.from(mapOf())) - .build() - - assertThat(params._pathParam(0)).isEqualTo("message_id") - // out-of-bound path param - assertThat(params._pathParam(1)).isEqualTo("") - } - - @Test - fun body() { - val params = - MessageRestoreParams.builder() - .messageId("message_id") - .body(JsonValue.from(mapOf())) - .build() - - val body = params._body() - - assertThat(body).isEqualTo(JsonValue.from(mapOf())) - } -} diff --git a/courier-java-core/src/test/kotlin/com/courier/services/async/inbox/MessageServiceAsyncTest.kt b/courier-java-core/src/test/kotlin/com/courier/services/async/inbox/MessageServiceAsyncTest.kt deleted file mode 100644 index 444389b..0000000 --- a/courier-java-core/src/test/kotlin/com/courier/services/async/inbox/MessageServiceAsyncTest.kt +++ /dev/null @@ -1,40 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.services.async.inbox - -import com.courier.client.okhttp.CourierOkHttpClientAsync -import com.courier.core.JsonValue -import com.courier.models.inbox.messages.MessageRestoreParams -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test - -internal class MessageServiceAsyncTest { - - @Disabled("Mock server tests are disabled") - @Test - fun delete() { - val client = CourierOkHttpClientAsync.builder().apiKey("My API Key").build() - val messageServiceAsync = client.inbox().messages() - - val future = messageServiceAsync.delete("message_id") - - val response = future.get() - } - - @Disabled("Mock server tests are disabled") - @Test - fun restore() { - val client = CourierOkHttpClientAsync.builder().apiKey("My API Key").build() - val messageServiceAsync = client.inbox().messages() - - val future = - messageServiceAsync.restore( - MessageRestoreParams.builder() - .messageId("message_id") - .body(JsonValue.from(mapOf())) - .build() - ) - - val response = future.get() - } -} diff --git a/courier-java-core/src/test/kotlin/com/courier/services/blocking/inbox/MessageServiceTest.kt b/courier-java-core/src/test/kotlin/com/courier/services/blocking/inbox/MessageServiceTest.kt deleted file mode 100644 index a9fd08a..0000000 --- a/courier-java-core/src/test/kotlin/com/courier/services/blocking/inbox/MessageServiceTest.kt +++ /dev/null @@ -1,35 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.courier.services.blocking.inbox - -import com.courier.client.okhttp.CourierOkHttpClient -import com.courier.core.JsonValue -import com.courier.models.inbox.messages.MessageRestoreParams -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test - -internal class MessageServiceTest { - - @Disabled("Mock server tests are disabled") - @Test - fun delete() { - val client = CourierOkHttpClient.builder().apiKey("My API Key").build() - val messageService = client.inbox().messages() - - messageService.delete("message_id") - } - - @Disabled("Mock server tests are disabled") - @Test - fun restore() { - val client = CourierOkHttpClient.builder().apiKey("My API Key").build() - val messageService = client.inbox().messages() - - messageService.restore( - MessageRestoreParams.builder() - .messageId("message_id") - .body(JsonValue.from(mapOf())) - .build() - ) - } -} diff --git a/courier-java-proguard-test/src/test/kotlin/com/courier/proguard/ProGuardCompatibilityTest.kt b/courier-java-proguard-test/src/test/kotlin/com/courier/proguard/ProGuardCompatibilityTest.kt index 083e50c..a1fda09 100644 --- a/courier-java-proguard-test/src/test/kotlin/com/courier/proguard/ProGuardCompatibilityTest.kt +++ b/courier-java-proguard-test/src/test/kotlin/com/courier/proguard/ProGuardCompatibilityTest.kt @@ -62,7 +62,6 @@ internal class ProGuardCompatibilityTest { assertThat(client.digests()).isNotNull() assertThat(client.inbound()).isNotNull() assertThat(client.lists()).isNotNull() - assertThat(client.inbox()).isNotNull() assertThat(client.messages()).isNotNull() assertThat(client.requests()).isNotNull() assertThat(client.notifications()).isNotNull() From 375b0f16dfd7e9817a0fc0fb51aa05899eaa6ae7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2026 21:10:14 +0000 Subject: [PATCH 3/4] feat: Merge pull request #183 from trycourier/dantran/c-19684-api-spec-document-messagecontexttenant_id-on-journey-send spec: document message.context.tenant_id on journey send nodes (C-19684) --- .stats.yml | 4 +- .../courier/models/journeys/JourneyNode.kt | 8 +- .../models/journeys/JourneySendNode.kt | 254 ++++++++- .../journeys/JourneyCreateParamsTest.kt | 515 +++++++++++++----- .../models/journeys/JourneyNodeTest.kt | 4 + .../models/journeys/JourneySendNodeTest.kt | 3 + .../services/async/JourneyServiceAsyncTest.kt | 114 +++- .../services/blocking/JourneyServiceTest.kt | 114 +++- 8 files changed, 832 insertions(+), 184 deletions(-) diff --git a/.stats.yml b/.stats.yml index 06502c4..2b72539 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 145 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-b4485f5c4897c26d52a46aeb39b8a22415bcd529b0ad326fd43a30d7fadf1376.yml -openapi_spec_hash: db619c8991994dc8016fc4327f6917a2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-9074e771bd8042233d1c6d73d11ea3c41ee63f3639119deae5dc3b7a5655e568.yml +openapi_spec_hash: f09e821d35afa0ad0117a1d8eb9d4d16 config_hash: 3eb0070d128aef7a6da16173f7050177 diff --git a/courier-java-core/src/main/kotlin/com/courier/models/journeys/JourneyNode.kt b/courier-java-core/src/main/kotlin/com/courier/models/journeys/JourneyNode.kt index 2004bf1..218470f 100644 --- a/courier-java-core/src/main/kotlin/com/courier/models/journeys/JourneyNode.kt +++ b/courier-java-core/src/main/kotlin/com/courier/models/journeys/JourneyNode.kt @@ -71,7 +71,7 @@ private constructor( * Send to the recipient. A send node sources its content from EXACTLY ONE of `message.template` * (a single notification template) or `experiment` (an A/B split across weighted template * variants) — supplying both, or neither, is rejected. Optionally override the recipient - * address, delay the send, or attach `data`. + * address, send as a tenant, delay the send, or attach `data`. */ fun send(): Optional = Optional.ofNullable(send) @@ -177,7 +177,7 @@ private constructor( * Send to the recipient. A send node sources its content from EXACTLY ONE of `message.template` * (a single notification template) or `experiment` (an A/B split across weighted template * variants) — supplying both, or neither, is rejected. Optionally override the recipient - * address, delay the send, or attach `data`. + * address, send as a tenant, delay the send, or attach `data`. */ fun asSend(): JourneySendNode = send.getOrThrow("send") @@ -505,7 +505,7 @@ private constructor( * Send to the recipient. A send node sources its content from EXACTLY ONE of * `message.template` (a single notification template) or `experiment` (an A/B split across * weighted template variants) — supplying both, or neither, is rejected. Optionally - * override the recipient address, delay the send, or attach `data`. + * override the recipient address, send as a tenant, delay the send, or attach `data`. */ @JvmStatic fun ofSend(send: JourneySendNode) = JourneyNode(send = send) @@ -600,7 +600,7 @@ private constructor( * Send to the recipient. A send node sources its content from EXACTLY ONE of * `message.template` (a single notification template) or `experiment` (an A/B split across * weighted template variants) — supplying both, or neither, is rejected. Optionally - * override the recipient address, delay the send, or attach `data`. + * override the recipient address, send as a tenant, delay the send, or attach `data`. */ fun visitSend(send: JourneySendNode): T diff --git a/courier-java-core/src/main/kotlin/com/courier/models/journeys/JourneySendNode.kt b/courier-java-core/src/main/kotlin/com/courier/models/journeys/JourneySendNode.kt index d2e249c..1d05869 100644 --- a/courier-java-core/src/main/kotlin/com/courier/models/journeys/JourneySendNode.kt +++ b/courier-java-core/src/main/kotlin/com/courier/models/journeys/JourneySendNode.kt @@ -22,8 +22,8 @@ import kotlin.jvm.optionals.getOrNull /** * Send to the recipient. A send node sources its content from EXACTLY ONE of `message.template` (a * single notification template) or `experiment` (an A/B split across weighted template variants) — - * supplying both, or neither, is rejected. Optionally override the recipient address, delay the - * send, or attach `data`. + * supplying both, or neither, is rejected. Optionally override the recipient address, send as a + * tenant, delay the send, or attach `data`. */ class JourneySendNode @JsonCreator(mode = JsonCreator.Mode.DISABLED) @@ -348,6 +348,7 @@ private constructor( class Message @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( + private val context: JsonField, private val data: JsonField, private val delay: JsonField, private val template: JsonField, @@ -357,13 +358,23 @@ private constructor( @JsonCreator private constructor( + @JsonProperty("context") @ExcludeMissing context: JsonField = JsonMissing.of(), @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), @JsonProperty("delay") @ExcludeMissing delay: JsonField = JsonMissing.of(), @JsonProperty("template") @ExcludeMissing template: JsonField = JsonMissing.of(), @JsonProperty("to") @ExcludeMissing to: JsonField = JsonMissing.of(), - ) : this(data, delay, template, to, mutableMapOf()) + ) : this(context, data, delay, template, to, mutableMapOf()) + + /** + * Tenant context for this send. Set it to deliver on behalf of one of your customers, so + * the message uses that tenant's brand and settings. + * + * @throws CourierInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun context(): Optional = context.getOptional("context") /** * @throws CourierInvalidDataException if the JSON field has an unexpected type (e.g. if the @@ -389,6 +400,13 @@ private constructor( */ fun to(): Optional = to.getOptional("to") + /** + * Returns the raw JSON value of [context]. + * + * Unlike [context], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("context") @ExcludeMissing fun _context(): JsonField = context + /** * Returns the raw JSON value of [data]. * @@ -438,6 +456,7 @@ private constructor( /** A builder for [Message]. */ class Builder internal constructor() { + private var context: JsonField = JsonMissing.of() private var data: JsonField = JsonMissing.of() private var delay: JsonField = JsonMissing.of() private var template: JsonField = JsonMissing.of() @@ -446,6 +465,7 @@ private constructor( @JvmSynthetic internal fun from(message: Message) = apply { + context = message.context data = message.data delay = message.delay template = message.template @@ -453,6 +473,21 @@ private constructor( additionalProperties = message.additionalProperties.toMutableMap() } + /** + * Tenant context for this send. Set it to deliver on behalf of one of your customers, + * so the message uses that tenant's brand and settings. + */ + fun context(context: Context) = context(JsonField.of(context)) + + /** + * Sets [Builder.context] to an arbitrary JSON value. + * + * You should usually call [Builder.context] with a well-typed [Context] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun context(context: JsonField) = apply { this.context = context } + fun data(data: Data) = data(JsonField.of(data)) /** @@ -522,7 +557,7 @@ private constructor( * Further updates to this [Builder] will not mutate the returned instance. */ fun build(): Message = - Message(data, delay, template, to, additionalProperties.toMutableMap()) + Message(context, data, delay, template, to, additionalProperties.toMutableMap()) } private var validated: Boolean = false @@ -541,6 +576,7 @@ private constructor( return@apply } + context().ifPresent { it.validate() } data().ifPresent { it.validate() } delay().ifPresent { it.validate() } template() @@ -564,11 +600,214 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (data.asKnown().getOrNull()?.validity() ?: 0) + + (context.asKnown().getOrNull()?.validity() ?: 0) + + (data.asKnown().getOrNull()?.validity() ?: 0) + (delay.asKnown().getOrNull()?.validity() ?: 0) + (if (template.asKnown().isPresent) 1 else 0) + (to.asKnown().getOrNull()?.validity() ?: 0) + /** + * Tenant context for this send. Set it to deliver on behalf of one of your customers, so + * the message uses that tenant's brand and settings. + */ + class Context + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val tenantId: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("tenant_id") + @ExcludeMissing + tenantId: JsonField = JsonMissing.of() + ) : this(tenantId, mutableMapOf()) + + /** + * The tenant to send as. Accepts either a literal tenant id (`acme-tenant`) or a + * whole-string mustache reference to a value the run already holds — + * `{{data.tenant_id}}` from the invocation payload, or `{{f1.body.tenant_id}}` from the + * response of an earlier fetch node with id `f1`. A reference is resolved separately on + * every run, so a single journey can deliver as many tenants. Two forms are rejected + * with `400`: mid-string interpolation such as `tenant-{{data.region}}`, and any value + * beginning with `refs.`, which is reserved for internal use. A reference that resolves + * to nothing at run time does not stop the run — the message is still sent, with no + * tenant context — so make sure the referenced value is always present. `GET` returns + * the value in the same form it was supplied. + * + * @throws CourierInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun tenantId(): String = tenantId.getRequired("tenant_id") + + /** + * Returns the raw JSON value of [tenantId]. + * + * Unlike [tenantId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("tenant_id") @ExcludeMissing fun _tenantId(): JsonField = tenantId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Context]. + * + * The following fields are required: + * ```java + * .tenantId() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Context]. */ + class Builder internal constructor() { + + private var tenantId: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(context: Context) = apply { + tenantId = context.tenantId + additionalProperties = context.additionalProperties.toMutableMap() + } + + /** + * The tenant to send as. Accepts either a literal tenant id (`acme-tenant`) or a + * whole-string mustache reference to a value the run already holds — + * `{{data.tenant_id}}` from the invocation payload, or `{{f1.body.tenant_id}}` from + * the response of an earlier fetch node with id `f1`. A reference is resolved + * separately on every run, so a single journey can deliver as many tenants. Two + * forms are rejected with `400`: mid-string interpolation such as + * `tenant-{{data.region}}`, and any value beginning with `refs.`, which is reserved + * for internal use. A reference that resolves to nothing at run time does not stop + * the run — the message is still sent, with no tenant context — so make sure the + * referenced value is always present. `GET` returns the value in the same form it + * was supplied. + */ + fun tenantId(tenantId: String) = tenantId(JsonField.of(tenantId)) + + /** + * Sets [Builder.tenantId] to an arbitrary JSON value. + * + * You should usually call [Builder.tenantId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun tenantId(tenantId: JsonField) = apply { this.tenantId = tenantId } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Context]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .tenantId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Context = + Context( + checkRequired("tenantId", tenantId), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws CourierInvalidDataException if any value type in this object doesn't match + * its expected type. + */ + fun validate(): Context = apply { + if (validated) { + return@apply + } + + tenantId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CourierInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = (if (tenantId.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Context && + tenantId == other.tenantId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(tenantId, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Context{tenantId=$tenantId, additionalProperties=$additionalProperties}" + } + class Data @JsonCreator private constructor( @@ -1149,6 +1388,7 @@ private constructor( } return other is Message && + context == other.context && data == other.data && delay == other.delay && template == other.template && @@ -1157,13 +1397,13 @@ private constructor( } private val hashCode: Int by lazy { - Objects.hash(data, delay, template, to, additionalProperties) + Objects.hash(context, data, delay, template, to, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Message{data=$data, delay=$delay, template=$template, to=$to, additionalProperties=$additionalProperties}" + "Message{context=$context, data=$data, delay=$delay, template=$template, to=$to, additionalProperties=$additionalProperties}" } class Type @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneyCreateParamsTest.kt b/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneyCreateParamsTest.kt index 2390c4e..7b6888e 100644 --- a/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneyCreateParamsTest.kt +++ b/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneyCreateParamsTest.kt @@ -17,31 +17,89 @@ internal class JourneyCreateParamsTest { .createJourneyRequest( CreateJourneyRequest.builder() .name("Welcome Journey") - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("trigger-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .nodes( + listOf( + JourneyNode.ofApiInvokeTrigger( + JourneyApiInvokeTriggerNode.builder() + .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) + .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) + .id("trigger-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .schema( + JourneyApiInvokeTriggerNode.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() - ) - .build() - ) - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("send-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + ), + JourneyNode.ofSend( + JourneySendNode.builder() + .message( + JourneySendNode.Message.builder() + .context( + JourneySendNode.Message.Context.builder() + .tenantId("x") + .build() + ) + .data( + JourneySendNode.Message.Data.builder() + .putAdditionalProperty( + "foo", + JsonValue.from("bar"), + ) + .build() + ) + .delay( + JourneySendNode.Message.Delay.builder() + .until("x") + .timezone("x") + .build() + ) + .template("nt_01kx4h2jdafq8bk9aftxak4b40") + .to( + JourneySendNode.Message.To.builder() + .emailOverride("x") + .phoneNumberOverride("x") + .userIdOverride("x") + .build() + ) + .build() + ) + .type(JourneySendNode.Type.SEND) + .id("send-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .experiment( + JourneyExperiment.builder() + .bucketingKey("x") + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .id("x") + .name("name") + .build() + ) .build() - ) - .build() + ), + JourneyNode.ofExit( + JourneyExitNode.builder() + .type(JourneyExitNode.Type.EXIT) + .id("exit-1") + .build() + ), + ) ) .enabled(true) .state(JourneyState.DRAFT) @@ -59,31 +117,91 @@ internal class JourneyCreateParamsTest { .createJourneyRequest( CreateJourneyRequest.builder() .name("Welcome Journey") - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("trigger-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .nodes( + listOf( + JourneyNode.ofApiInvokeTrigger( + JourneyApiInvokeTriggerNode.builder() + .triggerType( + JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE + ) + .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) + .id("trigger-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .schema( + JourneyApiInvokeTriggerNode.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() - ) - .build() - ) - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("send-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + ), + JourneyNode.ofSend( + JourneySendNode.builder() + .message( + JourneySendNode.Message.builder() + .context( + JourneySendNode.Message.Context.builder() + .tenantId("x") + .build() + ) + .data( + JourneySendNode.Message.Data.builder() + .putAdditionalProperty( + "foo", + JsonValue.from("bar"), + ) + .build() + ) + .delay( + JourneySendNode.Message.Delay.builder() + .until("x") + .timezone("x") + .build() + ) + .template("nt_01kx4h2jdafq8bk9aftxak4b40") + .to( + JourneySendNode.Message.To.builder() + .emailOverride("x") + .phoneNumberOverride("x") + .userIdOverride("x") + .build() + ) + .build() + ) + .type(JourneySendNode.Type.SEND) + .id("send-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .experiment( + JourneyExperiment.builder() + .bucketingKey("x") + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .id("x") + .name("name") + .build() + ) .build() - ) - .build() + ), + JourneyNode.ofExit( + JourneyExitNode.builder() + .type(JourneyExitNode.Type.EXIT) + .id("exit-1") + .build() + ), + ) ) .enabled(true) .state(JourneyState.DRAFT) @@ -109,17 +227,28 @@ internal class JourneyCreateParamsTest { .createJourneyRequest( CreateJourneyRequest.builder() .name("Welcome Journey") - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .build() - ) - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .build() + .nodes( + listOf( + JourneyNode.ofApiInvokeTrigger( + JourneyApiInvokeTriggerNode.builder() + .triggerType( + JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE + ) + .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) + .build() + ), + JourneyNode.ofSend( + JourneySendNode.builder() + .message(JourneySendNode.Message.builder().build()) + .type(JourneySendNode.Type.SEND) + .build() + ), + JourneyNode.ofExit( + JourneyExitNode.builder() + .type(JourneyExitNode.Type.EXIT) + .build() + ), + ) ) .build() ) @@ -139,31 +268,91 @@ internal class JourneyCreateParamsTest { .createJourneyRequest( CreateJourneyRequest.builder() .name("Welcome Journey") - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("trigger-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .nodes( + listOf( + JourneyNode.ofApiInvokeTrigger( + JourneyApiInvokeTriggerNode.builder() + .triggerType( + JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE + ) + .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) + .id("trigger-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .schema( + JourneyApiInvokeTriggerNode.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() - ) - .build() - ) - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("send-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + ), + JourneyNode.ofSend( + JourneySendNode.builder() + .message( + JourneySendNode.Message.builder() + .context( + JourneySendNode.Message.Context.builder() + .tenantId("x") + .build() + ) + .data( + JourneySendNode.Message.Data.builder() + .putAdditionalProperty( + "foo", + JsonValue.from("bar"), + ) + .build() + ) + .delay( + JourneySendNode.Message.Delay.builder() + .until("x") + .timezone("x") + .build() + ) + .template("nt_01kx4h2jdafq8bk9aftxak4b40") + .to( + JourneySendNode.Message.To.builder() + .emailOverride("x") + .phoneNumberOverride("x") + .userIdOverride("x") + .build() + ) + .build() + ) + .type(JourneySendNode.Type.SEND) + .id("send-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .experiment( + JourneyExperiment.builder() + .bucketingKey("x") + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .id("x") + .name("name") + .build() + ) + .build() + ), + JourneyNode.ofExit( + JourneyExitNode.builder() + .type(JourneyExitNode.Type.EXIT) + .id("exit-1") .build() - ) - .build() + ), + ) ) .enabled(true) .state(JourneyState.DRAFT) @@ -177,31 +366,89 @@ internal class JourneyCreateParamsTest { .isEqualTo( CreateJourneyRequest.builder() .name("Welcome Journey") - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("trigger-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .nodes( + listOf( + JourneyNode.ofApiInvokeTrigger( + JourneyApiInvokeTriggerNode.builder() + .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) + .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) + .id("trigger-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .schema( + JourneyApiInvokeTriggerNode.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() - ) - .build() - ) - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("send-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + ), + JourneyNode.ofSend( + JourneySendNode.builder() + .message( + JourneySendNode.Message.builder() + .context( + JourneySendNode.Message.Context.builder() + .tenantId("x") + .build() + ) + .data( + JourneySendNode.Message.Data.builder() + .putAdditionalProperty( + "foo", + JsonValue.from("bar"), + ) + .build() + ) + .delay( + JourneySendNode.Message.Delay.builder() + .until("x") + .timezone("x") + .build() + ) + .template("nt_01kx4h2jdafq8bk9aftxak4b40") + .to( + JourneySendNode.Message.To.builder() + .emailOverride("x") + .phoneNumberOverride("x") + .userIdOverride("x") + .build() + ) + .build() + ) + .type(JourneySendNode.Type.SEND) + .id("send-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .experiment( + JourneyExperiment.builder() + .bucketingKey("x") + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .id("x") + .name("name") + .build() + ) .build() - ) - .build() + ), + JourneyNode.ofExit( + JourneyExitNode.builder() + .type(JourneyExitNode.Type.EXIT) + .id("exit-1") + .build() + ), + ) ) .enabled(true) .state(JourneyState.DRAFT) @@ -216,17 +463,28 @@ internal class JourneyCreateParamsTest { .createJourneyRequest( CreateJourneyRequest.builder() .name("Welcome Journey") - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .build() - ) - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .build() + .nodes( + listOf( + JourneyNode.ofApiInvokeTrigger( + JourneyApiInvokeTriggerNode.builder() + .triggerType( + JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE + ) + .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) + .build() + ), + JourneyNode.ofSend( + JourneySendNode.builder() + .message(JourneySendNode.Message.builder().build()) + .type(JourneySendNode.Type.SEND) + .build() + ), + JourneyNode.ofExit( + JourneyExitNode.builder() + .type(JourneyExitNode.Type.EXIT) + .build() + ), + ) ) .build() ) @@ -238,17 +496,24 @@ internal class JourneyCreateParamsTest { .isEqualTo( CreateJourneyRequest.builder() .name("Welcome Journey") - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .build() - ) - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .build() + .nodes( + listOf( + JourneyNode.ofApiInvokeTrigger( + JourneyApiInvokeTriggerNode.builder() + .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) + .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) + .build() + ), + JourneyNode.ofSend( + JourneySendNode.builder() + .message(JourneySendNode.Message.builder().build()) + .type(JourneySendNode.Type.SEND) + .build() + ), + JourneyNode.ofExit( + JourneyExitNode.builder().type(JourneyExitNode.Type.EXIT).build() + ), + ) ) .build() ) diff --git a/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneyNodeTest.kt b/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneyNodeTest.kt index 853b261..0bf83ae 100644 --- a/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneyNodeTest.kt +++ b/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneyNodeTest.kt @@ -134,6 +134,7 @@ internal class JourneyNodeTest { JourneySendNode.builder() .message( JourneySendNode.Message.builder() + .context(JourneySendNode.Message.Context.builder().tenantId("x").build()) .data( JourneySendNode.Message.Data.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -206,6 +207,9 @@ internal class JourneyNodeTest { JourneySendNode.builder() .message( JourneySendNode.Message.builder() + .context( + JourneySendNode.Message.Context.builder().tenantId("x").build() + ) .data( JourneySendNode.Message.Data.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) diff --git a/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneySendNodeTest.kt b/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneySendNodeTest.kt index 95dc270..0f1c5ca 100644 --- a/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneySendNodeTest.kt +++ b/courier-java-core/src/test/kotlin/com/courier/models/journeys/JourneySendNodeTest.kt @@ -16,6 +16,7 @@ internal class JourneySendNodeTest { JourneySendNode.builder() .message( JourneySendNode.Message.builder() + .context(JourneySendNode.Message.Context.builder().tenantId("x").build()) .data( JourneySendNode.Message.Data.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -65,6 +66,7 @@ internal class JourneySendNodeTest { assertThat(journeySendNode.message()) .isEqualTo( JourneySendNode.Message.builder() + .context(JourneySendNode.Message.Context.builder().tenantId("x").build()) .data( JourneySendNode.Message.Data.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -118,6 +120,7 @@ internal class JourneySendNodeTest { JourneySendNode.builder() .message( JourneySendNode.Message.builder() + .context(JourneySendNode.Message.Context.builder().tenantId("x").build()) .data( JourneySendNode.Message.Data.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) diff --git a/courier-java-core/src/test/kotlin/com/courier/services/async/JourneyServiceAsyncTest.kt b/courier-java-core/src/test/kotlin/com/courier/services/async/JourneyServiceAsyncTest.kt index b2f63d7..f7f8267 100644 --- a/courier-java-core/src/test/kotlin/com/courier/services/async/JourneyServiceAsyncTest.kt +++ b/courier-java-core/src/test/kotlin/com/courier/services/async/JourneyServiceAsyncTest.kt @@ -9,12 +9,17 @@ import com.courier.models.journeys.CreateJourneyRequest import com.courier.models.journeys.JourneyApiInvokeTriggerNode import com.courier.models.journeys.JourneyCancelParams import com.courier.models.journeys.JourneyCreateParams +import com.courier.models.journeys.JourneyExitNode +import com.courier.models.journeys.JourneyExperiment +import com.courier.models.journeys.JourneyExperimentVariant import com.courier.models.journeys.JourneyInvokeParams import com.courier.models.journeys.JourneyListParams +import com.courier.models.journeys.JourneyNode import com.courier.models.journeys.JourneyPublishParams import com.courier.models.journeys.JourneyPublishRequest import com.courier.models.journeys.JourneyReplaceParams import com.courier.models.journeys.JourneyRetrieveParams +import com.courier.models.journeys.JourneySendNode import com.courier.models.journeys.JourneyState import com.courier.models.journeys.JourneysInvokeRequest import org.junit.jupiter.api.Disabled @@ -36,31 +41,94 @@ internal class JourneyServiceAsyncTest { .createJourneyRequest( CreateJourneyRequest.builder() .name("Welcome Journey") - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("trigger-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .nodes( + listOf( + JourneyNode.ofApiInvokeTrigger( + JourneyApiInvokeTriggerNode.builder() + .triggerType( + JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE + ) + .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) + .id("trigger-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .schema( + JourneyApiInvokeTriggerNode.Schema.builder() + .putAdditionalProperty( + "foo", + JsonValue.from("bar"), + ) + .build() + ) .build() - ) - .build() - ) - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("send-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + ), + JourneyNode.ofSend( + JourneySendNode.builder() + .message( + JourneySendNode.Message.builder() + .context( + JourneySendNode.Message.Context.builder() + .tenantId("x") + .build() + ) + .data( + JourneySendNode.Message.Data.builder() + .putAdditionalProperty( + "foo", + JsonValue.from("bar"), + ) + .build() + ) + .delay( + JourneySendNode.Message.Delay.builder() + .until("x") + .timezone("x") + .build() + ) + .template("nt_01kx4h2jdafq8bk9aftxak4b40") + .to( + JourneySendNode.Message.To.builder() + .emailOverride("x") + .phoneNumberOverride("x") + .userIdOverride("x") + .build() + ) + .build() + ) + .type(JourneySendNode.Type.SEND) + .id("send-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .experiment( + JourneyExperiment.builder() + .bucketingKey("x") + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .id("x") + .name("name") + .build() + ) .build() - ) - .build() + ), + JourneyNode.ofExit( + JourneyExitNode.builder() + .type(JourneyExitNode.Type.EXIT) + .id("exit-1") + .build() + ), + ) ) .enabled(true) .state(JourneyState.DRAFT) diff --git a/courier-java-core/src/test/kotlin/com/courier/services/blocking/JourneyServiceTest.kt b/courier-java-core/src/test/kotlin/com/courier/services/blocking/JourneyServiceTest.kt index b2d5a3c..18a7ef9 100644 --- a/courier-java-core/src/test/kotlin/com/courier/services/blocking/JourneyServiceTest.kt +++ b/courier-java-core/src/test/kotlin/com/courier/services/blocking/JourneyServiceTest.kt @@ -9,12 +9,17 @@ import com.courier.models.journeys.CreateJourneyRequest import com.courier.models.journeys.JourneyApiInvokeTriggerNode import com.courier.models.journeys.JourneyCancelParams import com.courier.models.journeys.JourneyCreateParams +import com.courier.models.journeys.JourneyExitNode +import com.courier.models.journeys.JourneyExperiment +import com.courier.models.journeys.JourneyExperimentVariant import com.courier.models.journeys.JourneyInvokeParams import com.courier.models.journeys.JourneyListParams +import com.courier.models.journeys.JourneyNode import com.courier.models.journeys.JourneyPublishParams import com.courier.models.journeys.JourneyPublishRequest import com.courier.models.journeys.JourneyReplaceParams import com.courier.models.journeys.JourneyRetrieveParams +import com.courier.models.journeys.JourneySendNode import com.courier.models.journeys.JourneyState import com.courier.models.journeys.JourneysInvokeRequest import org.junit.jupiter.api.Disabled @@ -36,31 +41,94 @@ internal class JourneyServiceTest { .createJourneyRequest( CreateJourneyRequest.builder() .name("Welcome Journey") - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("trigger-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .nodes( + listOf( + JourneyNode.ofApiInvokeTrigger( + JourneyApiInvokeTriggerNode.builder() + .triggerType( + JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE + ) + .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) + .id("trigger-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .schema( + JourneyApiInvokeTriggerNode.Schema.builder() + .putAdditionalProperty( + "foo", + JsonValue.from("bar"), + ) + .build() + ) .build() - ) - .build() - ) - .addNode( - JourneyApiInvokeTriggerNode.builder() - .triggerType(JourneyApiInvokeTriggerNode.TriggerType.API_INVOKE) - .type(JourneyApiInvokeTriggerNode.Type.TRIGGER) - .id("send-1") - .conditionsOfConditionAtom(listOf("string", "string")) - .schema( - JourneyApiInvokeTriggerNode.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + ), + JourneyNode.ofSend( + JourneySendNode.builder() + .message( + JourneySendNode.Message.builder() + .context( + JourneySendNode.Message.Context.builder() + .tenantId("x") + .build() + ) + .data( + JourneySendNode.Message.Data.builder() + .putAdditionalProperty( + "foo", + JsonValue.from("bar"), + ) + .build() + ) + .delay( + JourneySendNode.Message.Delay.builder() + .until("x") + .timezone("x") + .build() + ) + .template("nt_01kx4h2jdafq8bk9aftxak4b40") + .to( + JourneySendNode.Message.To.builder() + .emailOverride("x") + .phoneNumberOverride("x") + .userIdOverride("x") + .build() + ) + .build() + ) + .type(JourneySendNode.Type.SEND) + .id("send-1") + .conditionsOfConditionAtom(listOf("string", "string")) + .experiment( + JourneyExperiment.builder() + .bucketingKey("x") + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .addVariant( + JourneyExperimentVariant.builder() + .id("x") + .templateId("x") + .weight(0.0) + .name("name") + .build() + ) + .id("x") + .name("name") + .build() + ) .build() - ) - .build() + ), + JourneyNode.ofExit( + JourneyExitNode.builder() + .type(JourneyExitNode.Type.EXIT) + .id("exit-1") + .build() + ), + ) ) .enabled(true) .state(JourneyState.DRAFT) From b29f52003943ef9e1bce444dee03619d04d1a9b6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2026 21:10:38 +0000 Subject: [PATCH 4/4] release: 4.25.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 10 ++++++++++ build.gradle.kts | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0f2463a..141929c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.24.0" + ".": "4.25.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dd13d0..6b49887 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 4.25.0 (2026-08-03) + +Full Changelog: [v4.24.0...v4.25.0](https://github.com/trycourier/courier-java/compare/v4.24.0...v4.25.0) + +### Features + +* Merge pull request [#183](https://github.com/trycourier/courier-java/issues/183) from trycourier/dantran/c-19684-api-spec-document-messagecontexttenant_id-on-journey-send ([375b0f1](https://github.com/trycourier/courier-java/commit/375b0f16dfd7e9817a0fc0fb51aa05899eaa6ae7)) +* spec: remove inbox message delete/restore endpoints for now (C-19268) ([#182](https://github.com/trycourier/courier-java/issues/182)) ([07e30e0](https://github.com/trycourier/courier-java/commit/07e30e0228b6de99301269f039ebba887c5dff47)) +* spec: reorder API reference sections to match the Studio nav ([#180](https://github.com/trycourier/courier-java/issues/180)) ([3fe56cc](https://github.com/trycourier/courier-java/commit/3fe56ccad1fcdce5235c1ef4e3c2613879384d59)) + ## 4.24.0 (2026-07-29) Full Changelog: [v4.23.0...v4.24.0](https://github.com/trycourier/courier-java/compare/v4.23.0...v4.24.0) diff --git a/build.gradle.kts b/build.gradle.kts index b4c977c..0e25458 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { allprojects { group = "com.courier" - version = "4.24.0" // x-release-please-version + version = "4.25.0" // x-release-please-version } subprojects {