From dd2bca38596e4ef7626ef23d1a73ce7678a4375e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 05:33:42 +0000 Subject: [PATCH 01/63] feat(client): add `HttpRequest#url()` method --- LICENSE | 2 +- .../com/blooio/api/core/http/HttpRequest.kt | 30 +++++ .../blooio/api/core/http/HttpRequestTest.kt | 110 ++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/core/http/HttpRequestTest.kt diff --git a/LICENSE b/LICENSE index 789f1c0..ce4ae4d 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Blooio + Copyright 2026 Blooio Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/HttpRequest.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/HttpRequest.kt index 7c10228..5bb901b 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/HttpRequest.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/HttpRequest.kt @@ -2,6 +2,7 @@ package com.blooio.api.core.http import com.blooio.api.core.checkRequired import com.blooio.api.core.toImmutable +import java.net.URLEncoder class HttpRequest private constructor( @@ -13,6 +14,35 @@ private constructor( @get:JvmName("body") val body: HttpRequestBody?, ) { + fun url(): String = buildString { + append(baseUrl) + + pathSegments.forEach { segment -> + if (!endsWith("/")) { + append("/") + } + append(URLEncoder.encode(segment, "UTF-8")) + } + + if (queryParams.isEmpty()) { + return@buildString + } + + append("?") + var isFirst = true + queryParams.keys().forEach { key -> + queryParams.values(key).forEach { value -> + if (!isFirst) { + append("&") + } + append(URLEncoder.encode(key, "UTF-8")) + append("=") + append(URLEncoder.encode(value, "UTF-8")) + isFirst = false + } + } + } + fun toBuilder(): Builder = Builder().from(this) override fun toString(): String = diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/core/http/HttpRequestTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/core/http/HttpRequestTest.kt new file mode 100644 index 0000000..57d1430 --- /dev/null +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/core/http/HttpRequestTest.kt @@ -0,0 +1,110 @@ +package com.blooio.api.core.http + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +internal class HttpRequestTest { + + enum class UrlTestCase(val request: HttpRequest, val expectedUrl: String) { + BASE_URL_ONLY( + HttpRequest.builder().method(HttpMethod.GET).baseUrl("https://api.example.com").build(), + expectedUrl = "https://api.example.com", + ), + BASE_URL_WITH_TRAILING_SLASH( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com/") + .build(), + expectedUrl = "https://api.example.com/", + ), + SINGLE_PATH_SEGMENT( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .build(), + expectedUrl = "https://api.example.com/users", + ), + MULTIPLE_PATH_SEGMENTS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegments("users", "123", "profile") + .build(), + expectedUrl = "https://api.example.com/users/123/profile", + ), + PATH_SEGMENT_WITH_SPECIAL_CHARS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("user name") + .build(), + expectedUrl = "https://api.example.com/user+name", + ), + SINGLE_QUERY_PARAM( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .putQueryParam("limit", "10") + .build(), + expectedUrl = "https://api.example.com/users?limit=10", + ), + MULTIPLE_QUERY_PARAMS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .putQueryParam("limit", "10") + .putQueryParam("offset", "20") + .build(), + expectedUrl = "https://api.example.com/users?limit=10&offset=20", + ), + QUERY_PARAM_WITH_SPECIAL_CHARS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("search") + .putQueryParam("q", "hello world") + .build(), + expectedUrl = "https://api.example.com/search?q=hello+world", + ), + MULTIPLE_VALUES_SAME_PARAM( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .putQueryParams("tags", listOf("admin", "user")) + .build(), + expectedUrl = "https://api.example.com/users?tags=admin&tags=user", + ), + BASE_URL_WITH_TRAILING_SLASH_AND_PATH( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com/") + .addPathSegment("users") + .build(), + expectedUrl = "https://api.example.com/users", + ), + COMPLEX_URL( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl("https://api.example.com") + .addPathSegments("v1", "users", "123") + .putQueryParams("include", listOf("profile", "settings")) + .putQueryParam("format", "json") + .build(), + expectedUrl = + "https://api.example.com/v1/users/123?include=profile&include=settings&format=json", + ), + } + + @ParameterizedTest + @EnumSource + fun url(testCase: UrlTestCase) { + val actualUrl = testCase.request.url() + + assertThat(actualUrl).isEqualTo(testCase.expectedUrl) + } +} From 4f0db3097b9b0c1876887115146216c0b3a50c30 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 04:54:47 +0000 Subject: [PATCH 02/63] feat(client): allow configuring dispatcher executor service --- .../api/client/okhttp/BlooioOkHttpClient.kt | 22 +++++++++++++++++++ .../client/okhttp/BlooioOkHttpClientAsync.kt | 22 +++++++++++++++++++ .../blooio/api/client/okhttp/OkHttpClient.kt | 9 ++++++++ 3 files changed, 53 insertions(+) diff --git a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt index 1d24917..e4722d3 100644 --- a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt +++ b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt @@ -16,6 +16,7 @@ import java.net.Proxy import java.time.Clock import java.time.Duration import java.util.Optional +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -44,11 +45,31 @@ class BlooioOkHttpClient private constructor() { class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + /** + * The executor service to use for running HTTP requests. + * + * Defaults to OkHttp's + * [default executor service](https://github.com/square/okhttp/blob/ace792f443b2ffb17974f5c0d1cecdf589309f26/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt#L98-L104). + * + * This class takes ownership of the executor service and shuts it down when closed. + */ + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + + /** + * Alias for calling [Builder.dispatcherExecutorService] with + * `dispatcherExecutorService.orElse(null)`. + */ + fun dispatcherExecutorService(dispatcherExecutorService: Optional) = + dispatcherExecutorService(dispatcherExecutorService.getOrNull()) + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ @@ -297,6 +318,7 @@ class BlooioOkHttpClient private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) diff --git a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt index d5e7916..3572e6a 100644 --- a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt +++ b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt @@ -16,6 +16,7 @@ import java.net.Proxy import java.time.Clock import java.time.Duration import java.util.Optional +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -44,11 +45,31 @@ class BlooioOkHttpClientAsync private constructor() { class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + /** + * The executor service to use for running HTTP requests. + * + * Defaults to OkHttp's + * [default executor service](https://github.com/square/okhttp/blob/ace792f443b2ffb17974f5c0d1cecdf589309f26/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt#L98-L104). + * + * This class takes ownership of the executor service and shuts it down when closed. + */ + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + + /** + * Alias for calling [Builder.dispatcherExecutorService] with + * `dispatcherExecutorService.orElse(null)`. + */ + fun dispatcherExecutorService(dispatcherExecutorService: Optional) = + dispatcherExecutorService(dispatcherExecutorService.getOrNull()) + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ @@ -297,6 +318,7 @@ class BlooioOkHttpClientAsync private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) diff --git a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt index a5565a5..91b0eff 100644 --- a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt +++ b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt @@ -15,11 +15,13 @@ import java.net.Proxy import java.time.Duration import java.util.concurrent.CancellationException import java.util.concurrent.CompletableFuture +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager import okhttp3.Call import okhttp3.Callback +import okhttp3.Dispatcher import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType @@ -198,6 +200,7 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien private var timeout: Timeout = Timeout.default() private var proxy: Proxy? = null + private var dispatcherExecutorService: ExecutorService? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null @@ -208,6 +211,10 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply { this.sslSocketFactory = sslSocketFactory } @@ -229,6 +236,8 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien .callTimeout(timeout.request()) .proxy(proxy) .apply { + dispatcherExecutorService?.let { dispatcher(Dispatcher(it)) } + val sslSocketFactory = sslSocketFactory val trustManager = trustManager if (sslSocketFactory != null && trustManager != null) { From d7905093b659e696e05478ee514fbbad370cc9d0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 08:40:08 +0000 Subject: [PATCH 03/63] chore(internal): support uploading Maven repo artifacts to stainless package server --- .github/workflows/ci.yml | 18 ++++ .../src/main/kotlin/blooio.publish.gradle.kts | 8 ++ scripts/upload-artifacts | 96 +++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100755 scripts/upload-artifacts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a7202d..66fee98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,9 @@ jobs: build: timeout-minutes: 15 name: build + permissions: + contents: read + id-token: write runs-on: ${{ github.repository == 'stainless-sdks/blooio-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork @@ -61,6 +64,21 @@ jobs: - name: Build SDK run: ./scripts/build + - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/blooio-java' + id: github-oidc + uses: actions/github-script@v6 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Build and upload Maven artifacts + if: github.repository == 'stainless-sdks/blooio-java' + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + PROJECT: blooio-java + run: ./scripts/upload-artifacts test: timeout-minutes: 15 name: test diff --git a/buildSrc/src/main/kotlin/blooio.publish.gradle.kts b/buildSrc/src/main/kotlin/blooio.publish.gradle.kts index 89bd9b0..e83dae5 100644 --- a/buildSrc/src/main/kotlin/blooio.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/blooio.publish.gradle.kts @@ -39,6 +39,14 @@ configure { } } } + repositories { + if (project.hasProperty("publishLocal")) { + maven { + name = "LocalFileSystem" + url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") + } + } + } } signing { diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts new file mode 100755 index 0000000..729e6f2 --- /dev/null +++ b/scripts/upload-artifacts @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# ANSI Color Codes +GREEN='\033[32m' +RED='\033[31m' +NC='\033[0m' # No Color + +log_error() { + local msg="$1" + local headers="$2" + local body="$3" + echo -e "${RED}${msg}${NC}" + [[ -f "$headers" ]] && echo -e "${RED}Headers:$(cat "$headers")${NC}" + echo -e "${RED}Body: ${body}${NC}" + exit 1 +} + +upload_file() { + local file_name="$1" + local tmp_headers + tmp_headers=$(mktemp) + + if [ -f "$file_name" ]; then + echo -e "${GREEN}Processing file: $file_name${NC}" + pkg_file_name="mvn${file_name#./build/local-maven-repo}" + + # Get signed URL for uploading artifact file + signed_url_response=$(curl -X POST -G "$URL" \ + -sS --retry 5 \ + -D "$tmp_headers" \ + --data-urlencode "filename=$pkg_file_name" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + + # Validate JSON and extract URL + if ! signed_url=$(echo "$signed_url_response" | jq -e -r '.url' 2>/dev/null) || [[ "$signed_url" == "null" ]]; then + log_error "Failed to get valid signed URL" "$tmp_headers" "$signed_url_response" + fi + + # Set content-type based on file extension + local extension="${file_name##*.}" + local content_type + case "$extension" in + jar) content_type="application/java-archive" ;; + md5|sha1|sha256|sha512) content_type="text/plain" ;; + module) content_type="application/json" ;; + pom|xml) content_type="application/xml" ;; + *) content_type="application/octet-stream" ;; + esac + + # Upload file + upload_response=$(curl -v -X PUT \ + --retry 5 \ + -D "$tmp_headers" \ + -H "Content-Type: $content_type" \ + --data-binary "@${file_name}" "$signed_url" 2>&1) + + if ! echo "$upload_response" | grep -q "HTTP/[0-9.]* 200"; then + log_error "Failed upload artifact file" "$tmp_headers" "$upload_response" + fi + + # Insert small throttle to reduce rate limiting risk + sleep 0.1 + fi +} + +walk_tree() { + local current_dir="$1" + + for entry in "$current_dir"/*; do + # Check that entry is valid + [ -e "$entry" ] || [ -h "$entry" ] || continue + + if [ -d "$entry" ]; then + walk_tree "$entry" + else + upload_file "$entry" + fi + done +} + +cd "$(dirname "$0")/.." + +echo "::group::Creating local Maven content" +./gradlew publishMavenPublicationToLocalFileSystemRepository -PpublishLocal +echo "::endgroup::" + +echo "::group::Uploading to pkg.stainless.com" +walk_tree "./build/local-maven-repo" +echo "::endgroup::" + +echo "::group::Generating instructions" +echo "Configure maven or gradle to use the repo located at 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'" +echo "::endgroup::" From d441da9aa8607881a63e2ed14b9037fcccf1600d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 04:25:14 +0000 Subject: [PATCH 04/63] chore(internal): clean up maven repo artifact script and add html documentation to repo root --- scripts/upload-artifacts | 44 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts index 729e6f2..df0c8d9 100755 --- a/scripts/upload-artifacts +++ b/scripts/upload-artifacts @@ -7,6 +7,8 @@ GREEN='\033[32m' RED='\033[31m' NC='\033[0m' # No Color +MAVEN_REPO_PATH="./build/local-maven-repo" + log_error() { local msg="$1" local headers="$2" @@ -24,7 +26,7 @@ upload_file() { if [ -f "$file_name" ]; then echo -e "${GREEN}Processing file: $file_name${NC}" - pkg_file_name="mvn${file_name#./build/local-maven-repo}" + pkg_file_name="mvn${file_name#"${MAVEN_REPO_PATH}"}" # Get signed URL for uploading artifact file signed_url_response=$(curl -X POST -G "$URL" \ @@ -47,6 +49,7 @@ upload_file() { md5|sha1|sha256|sha512) content_type="text/plain" ;; module) content_type="application/json" ;; pom|xml) content_type="application/xml" ;; + html) content_type="text/html" ;; *) content_type="application/octet-stream" ;; esac @@ -81,6 +84,41 @@ walk_tree() { done } +generate_instructions() { + cat << EOF > "$MAVEN_REPO_PATH/index.html" + + + + Maven Repo + + +

Stainless SDK Maven Repository

+

This is the Maven repository for your Stainless Java SDK build.

+ +

Directions

+

To use the uploaded Maven repository, add the following to your project's pom.xml:

+
<repositories>
+    <repository>
+        <id>stainless-sdk-repo</id>
+        <url>https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn</url>
+    </repository>
+</repositories>
+ +

If you're using Gradle, add the following to your build.gradle file:

+
repositories {
+    maven {
+        url 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'
+    }
+}
+ + +EOF + upload_file "${MAVEN_REPO_PATH}/index.html" + + echo "Configure maven or gradle to use the repo located at 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'" + echo "For more details, see the directions in https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn/index.html" +} + cd "$(dirname "$0")/.." echo "::group::Creating local Maven content" @@ -88,9 +126,9 @@ echo "::group::Creating local Maven content" echo "::endgroup::" echo "::group::Uploading to pkg.stainless.com" -walk_tree "./build/local-maven-repo" +walk_tree "$MAVEN_REPO_PATH" echo "::endgroup::" echo "::group::Generating instructions" -echo "Configure maven or gradle to use the repo located at 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'" +generate_instructions echo "::endgroup::" From b2ac60a271022b4f389feee2e73467927b2c7a51 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 05:57:36 +0000 Subject: [PATCH 05/63] chore: test on Jackson 2.14.0 to avoid encountering FasterXML/jackson-databind#3240 in tests fix: date time deserialization leniency --- README.md | 2 ++ blooio-java-core/build.gradle.kts | 18 +++++----- .../com/blooio/api/core/ObjectMappers.kt | 33 ++++++++++++------- .../com/blooio/api/core/ObjectMappersTest.kt | 16 +++------ blooio-java-proguard-test/build.gradle.kts | 2 +- 5 files changed, 38 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 0ec93d0..2fc28b7 100644 --- a/README.md +++ b/README.md @@ -258,6 +258,8 @@ If the SDK threw an exception, but you're _certain_ the version is compatible, t > [!CAUTION] > We make no guarantee that the SDK works correctly when the Jackson version check is disabled. +Also note that there are bugs in older Jackson versions that can affect the SDK. We don't work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead. + ## Network options ### Retries diff --git a/blooio-java-core/build.gradle.kts b/blooio-java-core/build.gradle.kts index 813acf4..8a19d0f 100644 --- a/blooio-java-core/build.gradle.kts +++ b/blooio-java-core/build.gradle.kts @@ -5,14 +5,16 @@ plugins { configurations.all { resolutionStrategy { - // Compile and test against a lower Jackson version to ensure we're compatible with it. - // We publish with a higher version (see below) to ensure users depend on a secure version by default. - force("com.fasterxml.jackson.core:jackson-core:2.13.4") - force("com.fasterxml.jackson.core:jackson-databind:2.13.4") - force("com.fasterxml.jackson.core:jackson-annotations:2.13.4") - force("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.4") - force("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4") - force("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") + // Compile and test against a lower Jackson version to ensure we're compatible with it. Note that + // we generally support 2.13.4, but test against 2.14.0 because 2.13.4 has some annoying (but + // niche) bugs (users should upgrade if they encounter them). We publish with a higher version + // (see below) to ensure users depend on a secure version by default. + force("com.fasterxml.jackson.core:jackson-core:2.14.0") + force("com.fasterxml.jackson.core:jackson-databind:2.14.0") + force("com.fasterxml.jackson.core:jackson-annotations:2.14.0") + force("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.0") + force("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.0") + force("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.0") } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt index 555296c..259dcc0 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt @@ -24,6 +24,7 @@ import java.io.InputStream import java.time.DateTimeException import java.time.LocalDate import java.time.LocalDateTime +import java.time.OffsetDateTime import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.time.temporal.ChronoField @@ -36,7 +37,7 @@ fun jsonMapper(): JsonMapper = .addModule( SimpleModule() .addSerializer(InputStreamSerializer) - .addDeserializer(LocalDateTime::class.java, LenientLocalDateTimeDeserializer()) + .addDeserializer(OffsetDateTime::class.java, LenientOffsetDateTimeDeserializer()) ) .withCoercionConfig(LogicalType.Boolean) { it.setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) @@ -64,6 +65,12 @@ fun jsonMapper(): JsonMapper = .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) } + .withCoercionConfig(LogicalType.DateTime) { + it.setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) + } .withCoercionConfig(LogicalType.Array) { it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) @@ -124,10 +131,10 @@ private object InputStreamSerializer : BaseSerializer(InputStream:: } /** - * A deserializer that can deserialize [LocalDateTime] from datetimes, dates, and zoned datetimes. + * A deserializer that can deserialize [OffsetDateTime] from datetimes, dates, and zoned datetimes. */ -private class LenientLocalDateTimeDeserializer : - StdDeserializer(LocalDateTime::class.java) { +private class LenientOffsetDateTimeDeserializer : + StdDeserializer(OffsetDateTime::class.java) { companion object { @@ -141,7 +148,7 @@ private class LenientLocalDateTimeDeserializer : override fun logicalType(): LogicalType = LogicalType.DateTime - override fun deserialize(p: JsonParser, context: DeserializationContext?): LocalDateTime { + override fun deserialize(p: JsonParser, context: DeserializationContext): OffsetDateTime { val exceptions = mutableListOf() for (formatter in DATE_TIME_FORMATTERS) { @@ -149,18 +156,20 @@ private class LenientLocalDateTimeDeserializer : val temporal = formatter.parse(p.text) return when { - !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> - LocalDate.from(temporal).atStartOfDay() - !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> - LocalDateTime.from(temporal) - else -> ZonedDateTime.from(temporal).toLocalDateTime() - } + !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> + LocalDate.from(temporal).atStartOfDay() + !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> + LocalDateTime.from(temporal) + else -> ZonedDateTime.from(temporal).toLocalDateTime() + } + .atZone(context.timeZone.toZoneId()) + .toOffsetDateTime() } catch (e: DateTimeException) { exceptions.add(e) } } - throw JsonParseException(p, "Cannot parse `LocalDateTime` from value: ${p.text}").apply { + throw JsonParseException(p, "Cannot parse `OffsetDateTime` from value: ${p.text}").apply { exceptions.forEach { addSuppressed(it) } } } diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt index a6a39a5..68e7cd1 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt @@ -3,7 +3,7 @@ package com.blooio.api.core import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.exc.MismatchedInputException import com.fasterxml.jackson.module.kotlin.readValue -import java.time.LocalDateTime +import java.time.OffsetDateTime import kotlin.reflect.KClass import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.catchThrowable @@ -58,14 +58,6 @@ internal class ObjectMappersTest { LONG to DOUBLE, LONG to INTEGER, CLASS to MAP, - // These aren't actually valid, but coercion configs don't work for String until - // v2.14.0: https://github.com/FasterXML/jackson-databind/issues/3240 - // We currently test on v2.13.4. - BOOLEAN to STRING, - FLOAT to STRING, - DOUBLE to STRING, - INTEGER to STRING, - LONG to STRING, ) } } @@ -84,7 +76,7 @@ internal class ObjectMappersTest { } } - enum class LenientLocalDateTimeTestCase(val string: String) { + enum class LenientOffsetDateTimeTestCase(val string: String) { DATE("1998-04-21"), DATE_TIME("1998-04-21T04:00:00"), ZONED_DATE_TIME_1("1998-04-21T04:00:00+03:00"), @@ -93,10 +85,10 @@ internal class ObjectMappersTest { @ParameterizedTest @EnumSource - fun readLocalDateTime_lenient(testCase: LenientLocalDateTimeTestCase) { + fun readOffsetDateTime_lenient(testCase: LenientOffsetDateTimeTestCase) { val jsonMapper = jsonMapper() val json = jsonMapper.writeValueAsString(testCase.string) - assertDoesNotThrow { jsonMapper().readValue(json) } + assertDoesNotThrow { jsonMapper().readValue(json) } } } diff --git a/blooio-java-proguard-test/build.gradle.kts b/blooio-java-proguard-test/build.gradle.kts index 720f493..732343e 100644 --- a/blooio-java-proguard-test/build.gradle.kts +++ b/blooio-java-proguard-test/build.gradle.kts @@ -19,7 +19,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testImplementation("org.assertj:assertj-core:3.25.3") - testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") + testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.0") } tasks.shadowJar { From 24c2d4b5b8e3295a5218d2f999fd796fef269b88 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 05:59:54 +0000 Subject: [PATCH 06/63] chore(internal): improve maven repo docs --- scripts/upload-artifacts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts index df0c8d9..548d152 100755 --- a/scripts/upload-artifacts +++ b/scripts/upload-artifacts @@ -56,12 +56,13 @@ upload_file() { # Upload file upload_response=$(curl -v -X PUT \ --retry 5 \ + --retry-all-errors \ -D "$tmp_headers" \ -H "Content-Type: $content_type" \ --data-binary "@${file_name}" "$signed_url" 2>&1) if ! echo "$upload_response" | grep -q "HTTP/[0-9.]* 200"; then - log_error "Failed upload artifact file" "$tmp_headers" "$upload_response" + log_error "Failed to upload artifact file" "$tmp_headers" "$upload_response" fi # Insert small throttle to reduce rate limiting risk @@ -110,6 +111,10 @@ generate_instructions() { url 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn' } } + +

Once you've added the repository, you can include dependencies from it as usual. See your + project README + for more details.

EOF From 3ee28c5e8bd033c3d96134fb13903941de2e8735 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 06:03:53 +0000 Subject: [PATCH 07/63] fix(client): disallow coercion from float to int --- .../src/main/kotlin/com/blooio/api/core/ObjectMappers.kt | 1 + .../src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt index 259dcc0..b6bb175 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt @@ -48,6 +48,7 @@ fun jsonMapper(): JsonMapper = } .withCoercionConfig(LogicalType.Integer) { it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) .setCoercion(CoercionInputShape.String, CoercionAction.Fail) .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt index 68e7cd1..9d24494 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt @@ -46,11 +46,7 @@ internal class ObjectMappersTest { val VALID_CONVERSIONS = listOf( FLOAT to DOUBLE, - FLOAT to INTEGER, - FLOAT to LONG, DOUBLE to FLOAT, - DOUBLE to INTEGER, - DOUBLE to LONG, INTEGER to FLOAT, INTEGER to DOUBLE, INTEGER to LONG, From 8cfab13629687564f829968a161b50843d8ddc73 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 06:04:29 +0000 Subject: [PATCH 08/63] chore(internal): update `actions/checkout` version --- .github/workflows/ci.yml | 6 +++--- .github/workflows/publish-sonatype.yml | 2 +- .github/workflows/release-doctor.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 66fee98..54ddc37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 @@ -47,7 +47,7 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 @@ -85,7 +85,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/blooio-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index 11f4929..ca320c6 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 53c616f..2d36b26 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'Blooio/blooio-java-sdk' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Check release environment run: | From 2ddb8126d441b260c80b9ef3b87a24f9ce20b5be Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 06:05:51 +0000 Subject: [PATCH 09/63] fix(client): fully respect max retries fix(client): send retry count header for max retries 0 chore(internal): depend on packages directly in example --- .../blooio/api/client/okhttp/OkHttpClient.kt | 2 ++ .../api/core/http/RetryingHttpClient.kt | 20 +++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt index 91b0eff..f01ac88 100644 --- a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt +++ b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt @@ -230,6 +230,8 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien fun build(): OkHttpClient = OkHttpClient( okhttp3.OkHttpClient.Builder() + // `RetryingHttpClient` handles retries if the user enabled them. + .retryOnConnectionFailure(false) .connectTimeout(timeout.connect()) .readTimeout(timeout.read()) .writeTimeout(timeout.write()) diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt index 6f34419..f261e5f 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt @@ -31,10 +31,6 @@ private constructor( ) : HttpClient { override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { - if (!isRetryable(request) || maxRetries <= 0) { - return httpClient.execute(request, requestOptions) - } - var modifiedRequest = maybeAddIdempotencyHeader(request) // Don't send the current retry count in the headers if the caller set their own value. @@ -48,6 +44,10 @@ private constructor( modifiedRequest = setRetryCountHeader(modifiedRequest, retries) } + if (!isRetryable(modifiedRequest)) { + return httpClient.execute(modifiedRequest, requestOptions) + } + val response = try { val response = httpClient.execute(modifiedRequest, requestOptions) @@ -75,10 +75,6 @@ private constructor( request: HttpRequest, requestOptions: RequestOptions, ): CompletableFuture { - if (!isRetryable(request) || maxRetries <= 0) { - return httpClient.executeAsync(request, requestOptions) - } - val modifiedRequest = maybeAddIdempotencyHeader(request) // Don't send the current retry count in the headers if the caller set their own value. @@ -94,8 +90,12 @@ private constructor( val requestWithRetryCount = if (shouldSendRetryCount) setRetryCountHeader(request, retries) else request - return httpClient - .executeAsync(requestWithRetryCount, requestOptions) + val responseFuture = httpClient.executeAsync(requestWithRetryCount, requestOptions) + if (!isRetryable(requestWithRetryCount)) { + return responseFuture + } + + return responseFuture .handleAsync( fun( response: HttpResponse?, From 67eb04e66d48b47097af4e8d66f093688ff1f8ef Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 06:06:37 +0000 Subject: [PATCH 10/63] chore(ci): upgrade `actions/setup-java` --- .github/workflows/ci.yml | 6 +++--- .github/workflows/publish-sonatype.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54ddc37..7db322c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | @@ -50,7 +50,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | @@ -88,7 +88,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index ca320c6..2d81e3a 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | From 025972007906b16f60bb8dc09ff3433c752f4be0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 04:18:44 +0000 Subject: [PATCH 11/63] chore(internal): update maven repo doc to include authentication --- scripts/upload-artifacts | 64 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts index 548d152..10f3c70 100755 --- a/scripts/upload-artifacts +++ b/scripts/upload-artifacts @@ -96,8 +96,52 @@ generate_instructions() {

Stainless SDK Maven Repository

This is the Maven repository for your Stainless Java SDK build.

-

Directions

-

To use the uploaded Maven repository, add the following to your project's pom.xml:

+

Project configuration

+ +

The details depend on whether you're using Maven or Gradle as your build tool.

+ +

Maven

+ +

Add the following to your project's pom.xml:

+
<repositories>
+    <repository>
+        <id>stainless-sdk-repo</id>
+        <url>https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn</url>
+    </repository>
+</repositories>
+ +

Gradle

+

Add the following to your build.gradle file:

+
repositories {
+    maven {
+        url "https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn"
+    }
+}
+ +
+

Configuring authentication (if required)

+ +

Some accounts may require authentication to access the repository. If so, use the + following instructions, replacing YOUR_STAINLESS_API_TOKEN with your actual token.

+ +

Maven with authentication

+ +

First, ensure you have the following in your Maven settings.xml for repo authentication:

+
<servers>
+    <server>
+        <id>stainless-sdk-repo</id>
+        <configuration>
+            <httpHeaders>
+                <property>
+                    <name>Authorization</name>
+                    <value>Bearer YOUR_STAINLESS_API_TOKEN</value>
+                </property>
+            </httpHeaders>
+        </configuration>
+    </server>
+</servers>
+ +

Then, add the following to your project's pom.xml:

<repositories>
     <repository>
         <id>stainless-sdk-repo</id>
@@ -105,14 +149,24 @@ generate_instructions() {
     </repository>
 </repositories>
-

If you're using Gradle, add the following to your build.gradle file:

+

Gradle with authentication

+

Add the following to your build.gradle file:

repositories {
     maven {
-        url 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'
+        url "https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn"
+        credentials(HttpHeaderCredentials) {
+            name = "Authorization"
+            value = "Bearer YOUR_STAINLESS_API_TOKEN"
+        }
+        authentication {
+            header(HttpHeaderAuthentication)
+        }
     }
 }
+
-

Once you've added the repository, you can include dependencies from it as usual. See your +

Using the repository

+

Once you've configured the repository, you can include dependencies from it as usual. See your project README for more details.

From f6d45cddc950b7443fb661d4804c4986ef89c187 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 04:19:24 +0000 Subject: [PATCH 12/63] feat(client): send `X-Stainless-Kotlin-Version` header --- .../src/main/kotlin/com/blooio/api/core/ClientOptions.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/ClientOptions.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/ClientOptions.kt index 815c3e2..5d2f3a9 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/ClientOptions.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/ClientOptions.kt @@ -404,6 +404,7 @@ private constructor( headers.put("X-Stainless-Package-Version", getPackageVersion()) headers.put("X-Stainless-Runtime", "JRE") headers.put("X-Stainless-Runtime-Version", getJavaVersion()) + headers.put("X-Stainless-Kotlin-Version", KotlinVersion.CURRENT.toString()) apiKey.let { if (!it.isEmpty()) { headers.put("Authorization", "Bearer $it") From a636226690a94e032e7b7d6e8fcf9d2f373bcfc3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 05:45:03 +0000 Subject: [PATCH 13/63] docs: add comment for arbitrary value fields --- .../blooio/api/models/me/MeRetrieveResponse.kt | 18 ++++++++++++++++-- .../models/messages/MessageRetrieveResponse.kt | 9 ++++++++- .../api/models/messages/MessageSendParams.kt | 18 ++++++++++++++++-- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/me/MeRetrieveResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/me/MeRetrieveResponse.kt index 05b1a17..fb7c24c 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/models/me/MeRetrieveResponse.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/me/MeRetrieveResponse.kt @@ -71,7 +71,14 @@ private constructor( fun integrationDetails(): Optional = integrationDetails.getOptional("integration_details") - /** Custom metadata associated with the API key. */ + /** + * Custom metadata associated with the API key. + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = meRetrieveResponse.metadata().convert(MyClass.class); + * ``` + */ @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonValue = metadata /** @@ -614,7 +621,14 @@ private constructor( fun customerWebhookUrl(): Optional = customerWebhookUrl.getOptional("customer_webhook_url") - /** Integration-specific metadata. */ + /** + * Integration-specific metadata. + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = integrationDetails.metadata().convert(MyClass.class); + * ``` + */ @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonValue = metadata /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageRetrieveResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageRetrieveResponse.kt index 38a65f1..59a17ee 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageRetrieveResponse.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageRetrieveResponse.kt @@ -97,7 +97,14 @@ private constructor( */ fun messageId(): Optional = messageId.getOptional("message_id") - /** Original metadata provided plus system generated fields. */ + /** + * Original metadata provided plus system generated fields. + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = messageRetrieveResponse.metadata().convert(MyClass.class); + * ``` + */ @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonValue = metadata /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageSendParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageSendParams.kt index cf098d3..abccdd8 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageSendParams.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageSendParams.kt @@ -56,7 +56,14 @@ private constructor( */ fun attachments(): Optional> = body.attachments() - /** Arbitrary key/value pairs to associate with the message. */ + /** + * Arbitrary key/value pairs to associate with the message. + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = messageSendParams.metadata().convert(MyClass.class); + * ``` + */ fun _metadata(): JsonValue = body._metadata() /** @@ -377,7 +384,14 @@ private constructor( */ fun attachments(): Optional> = attachments.getOptional("attachments") - /** Arbitrary key/value pairs to associate with the message. */ + /** + * Arbitrary key/value pairs to associate with the message. + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = body.metadata().convert(MyClass.class); + * ``` + */ @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonValue = metadata /** From d3c3b9c5e26275edbc5897780f4338d88e65eb7d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 05:45:48 +0000 Subject: [PATCH 14/63] chore(internal): correct cache invalidation for `SKIP_MOCK_TESTS` --- buildSrc/src/main/kotlin/blooio.kotlin.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/buildSrc/src/main/kotlin/blooio.kotlin.gradle.kts b/buildSrc/src/main/kotlin/blooio.kotlin.gradle.kts index 42465f2..2ae7785 100644 --- a/buildSrc/src/main/kotlin/blooio.kotlin.gradle.kts +++ b/buildSrc/src/main/kotlin/blooio.kotlin.gradle.kts @@ -33,6 +33,9 @@ kotlin { tasks.withType().configureEach { systemProperty("junit.jupiter.execution.parallel.enabled", true) systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent") + + // `SKIP_MOCK_TESTS` affects which tests run so it must be added as input for proper cache invalidation. + inputs.property("skipMockTests", System.getenv("SKIP_MOCK_TESTS")).optional(true) } val ktfmt by configurations.creating From 573fcaf71930c387314fb18231334b542df8a47f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 05:48:29 +0000 Subject: [PATCH 15/63] fix(client): preserve time zone in lenient date-time parsing --- .../com/blooio/api/core/ObjectMappers.kt | 19 +++++---- .../com/blooio/api/core/ObjectMappersTest.kt | 41 +++++++++++++++---- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt index b6bb175..47b2466 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/ObjectMappers.kt @@ -25,7 +25,7 @@ import java.time.DateTimeException import java.time.LocalDate import java.time.LocalDateTime import java.time.OffsetDateTime -import java.time.ZonedDateTime +import java.time.ZoneId import java.time.format.DateTimeFormatter import java.time.temporal.ChronoField @@ -157,14 +157,15 @@ private class LenientOffsetDateTimeDeserializer : val temporal = formatter.parse(p.text) return when { - !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> - LocalDate.from(temporal).atStartOfDay() - !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> - LocalDateTime.from(temporal) - else -> ZonedDateTime.from(temporal).toLocalDateTime() - } - .atZone(context.timeZone.toZoneId()) - .toOffsetDateTime() + !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> + LocalDate.from(temporal) + .atStartOfDay() + .atZone(ZoneId.of("UTC")) + .toOffsetDateTime() + !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> + LocalDateTime.from(temporal).atZone(ZoneId.of("UTC")).toOffsetDateTime() + else -> OffsetDateTime.from(temporal) + } } catch (e: DateTimeException) { exceptions.add(e) } diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt index 9d24494..a787581 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/core/ObjectMappersTest.kt @@ -3,12 +3,14 @@ package com.blooio.api.core import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.exc.MismatchedInputException import com.fasterxml.jackson.module.kotlin.readValue +import java.time.LocalDate +import java.time.LocalTime import java.time.OffsetDateTime +import java.time.ZoneOffset import kotlin.reflect.KClass import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.catchThrowable import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.EnumSource import org.junitpioneer.jupiter.cartesian.CartesianTest @@ -72,11 +74,34 @@ internal class ObjectMappersTest { } } - enum class LenientOffsetDateTimeTestCase(val string: String) { - DATE("1998-04-21"), - DATE_TIME("1998-04-21T04:00:00"), - ZONED_DATE_TIME_1("1998-04-21T04:00:00+03:00"), - ZONED_DATE_TIME_2("1998-04-21T04:00:00Z"), + enum class LenientOffsetDateTimeTestCase( + val string: String, + val expectedOffsetDateTime: OffsetDateTime, + ) { + DATE( + "1998-04-21", + expectedOffsetDateTime = + OffsetDateTime.of(LocalDate.of(1998, 4, 21), LocalTime.of(0, 0), ZoneOffset.UTC), + ), + DATE_TIME( + "1998-04-21T04:00:00", + expectedOffsetDateTime = + OffsetDateTime.of(LocalDate.of(1998, 4, 21), LocalTime.of(4, 0), ZoneOffset.UTC), + ), + ZONED_DATE_TIME_1( + "1998-04-21T04:00:00+03:00", + expectedOffsetDateTime = + OffsetDateTime.of( + LocalDate.of(1998, 4, 21), + LocalTime.of(4, 0), + ZoneOffset.ofHours(3), + ), + ), + ZONED_DATE_TIME_2( + "1998-04-21T04:00:00Z", + expectedOffsetDateTime = + OffsetDateTime.of(LocalDate.of(1998, 4, 21), LocalTime.of(4, 0), ZoneOffset.UTC), + ), } @ParameterizedTest @@ -85,6 +110,8 @@ internal class ObjectMappersTest { val jsonMapper = jsonMapper() val json = jsonMapper.writeValueAsString(testCase.string) - assertDoesNotThrow { jsonMapper().readValue(json) } + val offsetDateTime = jsonMapper().readValue(json) + + assertThat(offsetDateTime).isEqualTo(testCase.expectedOffsetDateTime) } } From a32a19dcfbeff710c7c6c0b4daaa8ed98107294a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 24 Jan 2026 05:31:26 +0000 Subject: [PATCH 16/63] chore(ci): upgrade `actions/github-script` --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7db322c..2915cd2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,7 +67,7 @@ jobs: - name: Get GitHub OIDC Token if: github.repository == 'stainless-sdks/blooio-java' id: github-oidc - uses: actions/github-script@v6 + uses: actions/github-script@v8 with: script: core.setOutput('github_token', await core.getIDToken()); From a8da67050906f36094fdf4cf4fb278d6abe01f58 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 31 Jan 2026 06:45:51 +0000 Subject: [PATCH 17/63] chore(internal): allow passing args to `./scripts/test` --- scripts/build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build b/scripts/build index f406348..16a2b00 100755 --- a/scripts/build +++ b/scripts/build @@ -5,4 +5,4 @@ set -e cd "$(dirname "$0")/.." echo "==> Building classes" -./gradlew build testClasses -x test +./gradlew build testClasses "$@" -x test From 0c278a7a62ba05270a09d4ad6d4e0c1eadebd280 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 7 Feb 2026 08:04:15 +0000 Subject: [PATCH 18/63] chore(internal): upgrade AssertJ --- blooio-java-client-okhttp/build.gradle.kts | 2 +- blooio-java-core/build.gradle.kts | 2 +- blooio-java-proguard-test/build.gradle.kts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/blooio-java-client-okhttp/build.gradle.kts b/blooio-java-client-okhttp/build.gradle.kts index 3449d62..e556e32 100644 --- a/blooio-java-client-okhttp/build.gradle.kts +++ b/blooio-java-client-okhttp/build.gradle.kts @@ -10,6 +10,6 @@ dependencies { implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") testImplementation(kotlin("test")) - testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("org.assertj:assertj-core:3.27.7") testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2") } diff --git a/blooio-java-core/build.gradle.kts b/blooio-java-core/build.gradle.kts index 8a19d0f..f647be8 100644 --- a/blooio-java-core/build.gradle.kts +++ b/blooio-java-core/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation(project(":blooio-java-client-okhttp")) testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2") - testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("org.assertj:assertj-core:3.27.7") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.3") testImplementation("org.junit-pioneer:junit-pioneer:1.9.1") diff --git a/blooio-java-proguard-test/build.gradle.kts b/blooio-java-proguard-test/build.gradle.kts index 732343e..34ff8aa 100644 --- a/blooio-java-proguard-test/build.gradle.kts +++ b/blooio-java-proguard-test/build.gradle.kts @@ -18,7 +18,7 @@ dependencies { testImplementation(project(":blooio-java")) testImplementation(kotlin("test")) testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") - testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("org.assertj:assertj-core:3.27.7") testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.0") } From d5926e0c1019ba3d777459623b0b847a286c7b97 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 05:29:34 +0000 Subject: [PATCH 19/63] chore(internal): codegen related update --- .../com/blooio/api/TestServerExtension.kt | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/TestServerExtension.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/TestServerExtension.kt index c92a329..240b2e0 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/TestServerExtension.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/TestServerExtension.kt @@ -15,25 +15,12 @@ class TestServerExtension : BeforeAllCallback, ExecutionCondition { } catch (e: Exception) { throw RuntimeException( """ - The test suite will not run without a mock Prism server running against your OpenAPI spec. + The test suite will not run without a mock server running against your OpenAPI spec. You can set the environment variable `SKIP_MOCK_TESTS` to `true` to skip running any tests that require the mock server. - To fix: - - 1. Install Prism (requires Node 16+): - - With npm: - $ npm install -g @stoplight/prism-cli - - With yarn: - $ yarn global add @stoplight/prism-cli - - 2. Run the mock server - - To run the server, pass in the path of your OpenAPI spec to the prism command: - $ prism mock path/to/your.openapi.yml + To fix run `./scripts/mock` in a separate terminal. """ .trimIndent(), e, From cdac773c08fdbc1cfa3ddc812efaa40fb2da4a90 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 05:29:07 +0000 Subject: [PATCH 20/63] chore(internal): codegen related update --- README.md | 19 ++++++++ .../api/client/okhttp/BlooioOkHttpClient.kt | 44 +++++++++++++++++++ .../client/okhttp/BlooioOkHttpClientAsync.kt | 44 +++++++++++++++++++ .../blooio/api/client/okhttp/OkHttpClient.kt | 44 ++++++++++++++++++- 4 files changed, 150 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2fc28b7..1215874 100644 --- a/README.md +++ b/README.md @@ -333,6 +333,25 @@ BlooioClient client = BlooioOkHttpClient.builder() .build(); ``` +### Connection pooling + +To customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods: + +```java +import com.blooio.api.client.BlooioClient; +import com.blooio.api.client.okhttp.BlooioOkHttpClient; +import java.time.Duration; + +BlooioClient client = BlooioOkHttpClient.builder() + .fromEnv() + // If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa. + .maxIdleConnections(10) + .keepAliveDuration(Duration.ofMinutes(2)) + .build(); +``` + +If both options are unset, OkHttp's default connection pool settings are used. + ### HTTPS > [!NOTE] diff --git a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt index e4722d3..c409e2c 100644 --- a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt +++ b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt @@ -47,6 +47,8 @@ class BlooioOkHttpClient private constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null + private var maxIdleConnections: Int? = null + private var keepAliveDuration: Duration? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null @@ -75,6 +77,46 @@ class BlooioOkHttpClient private constructor() { /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ fun proxy(proxy: Optional) = proxy(proxy.getOrNull()) + /** + * The maximum number of idle connections kept by the underlying OkHttp connection pool. + * + * If this is set, then [keepAliveDuration] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun maxIdleConnections(maxIdleConnections: Int?) = apply { + this.maxIdleConnections = maxIdleConnections + } + + /** + * Alias for [Builder.maxIdleConnections]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun maxIdleConnections(maxIdleConnections: Int) = + maxIdleConnections(maxIdleConnections as Int?) + + /** + * Alias for calling [Builder.maxIdleConnections] with `maxIdleConnections.orElse(null)`. + */ + fun maxIdleConnections(maxIdleConnections: Optional) = + maxIdleConnections(maxIdleConnections.getOrNull()) + + /** + * The keep-alive duration for idle connections in the underlying OkHttp connection pool. + * + * If this is set, then [maxIdleConnections] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun keepAliveDuration(keepAliveDuration: Duration?) = apply { + this.keepAliveDuration = keepAliveDuration + } + + /** Alias for calling [Builder.keepAliveDuration] with `keepAliveDuration.orElse(null)`. */ + fun keepAliveDuration(keepAliveDuration: Optional) = + keepAliveDuration(keepAliveDuration.getOrNull()) + /** * The socket factory used to secure HTTPS connections. * @@ -318,6 +360,8 @@ class BlooioOkHttpClient private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .maxIdleConnections(maxIdleConnections) + .keepAliveDuration(keepAliveDuration) .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) diff --git a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt index 3572e6a..ccc14ff 100644 --- a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt +++ b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt @@ -47,6 +47,8 @@ class BlooioOkHttpClientAsync private constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null + private var maxIdleConnections: Int? = null + private var keepAliveDuration: Duration? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null @@ -75,6 +77,46 @@ class BlooioOkHttpClientAsync private constructor() { /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ fun proxy(proxy: Optional) = proxy(proxy.getOrNull()) + /** + * The maximum number of idle connections kept by the underlying OkHttp connection pool. + * + * If this is set, then [keepAliveDuration] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun maxIdleConnections(maxIdleConnections: Int?) = apply { + this.maxIdleConnections = maxIdleConnections + } + + /** + * Alias for [Builder.maxIdleConnections]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun maxIdleConnections(maxIdleConnections: Int) = + maxIdleConnections(maxIdleConnections as Int?) + + /** + * Alias for calling [Builder.maxIdleConnections] with `maxIdleConnections.orElse(null)`. + */ + fun maxIdleConnections(maxIdleConnections: Optional) = + maxIdleConnections(maxIdleConnections.getOrNull()) + + /** + * The keep-alive duration for idle connections in the underlying OkHttp connection pool. + * + * If this is set, then [maxIdleConnections] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun keepAliveDuration(keepAliveDuration: Duration?) = apply { + this.keepAliveDuration = keepAliveDuration + } + + /** Alias for calling [Builder.keepAliveDuration] with `keepAliveDuration.orElse(null)`. */ + fun keepAliveDuration(keepAliveDuration: Optional) = + keepAliveDuration(keepAliveDuration.getOrNull()) + /** * The socket factory used to secure HTTPS connections. * @@ -318,6 +360,8 @@ class BlooioOkHttpClientAsync private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .maxIdleConnections(maxIdleConnections) + .keepAliveDuration(keepAliveDuration) .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) diff --git a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt index f01ac88..ccb1cdf 100644 --- a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt +++ b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/OkHttpClient.kt @@ -16,11 +16,13 @@ import java.time.Duration import java.util.concurrent.CancellationException import java.util.concurrent.CompletableFuture import java.util.concurrent.ExecutorService +import java.util.concurrent.TimeUnit import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager import okhttp3.Call import okhttp3.Callback +import okhttp3.ConnectionPool import okhttp3.Dispatcher import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType @@ -33,7 +35,7 @@ import okhttp3.logging.HttpLoggingInterceptor import okio.BufferedSink class OkHttpClient -private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClient) : HttpClient { +internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClient) : HttpClient { override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { val call = newCall(request, requestOptions) @@ -200,6 +202,8 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien private var timeout: Timeout = Timeout.default() private var proxy: Proxy? = null + private var maxIdleConnections: Int? = null + private var keepAliveDuration: Duration? = null private var dispatcherExecutorService: ExecutorService? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null @@ -211,6 +215,28 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + /** + * Sets the maximum number of idle connections kept by the underlying [ConnectionPool]. + * + * If this is set, then [keepAliveDuration] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun maxIdleConnections(maxIdleConnections: Int?) = apply { + this.maxIdleConnections = maxIdleConnections + } + + /** + * Sets the keep-alive duration for idle connections in the underlying [ConnectionPool]. + * + * If this is set, then [maxIdleConnections] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun keepAliveDuration(keepAliveDuration: Duration?) = apply { + this.keepAliveDuration = keepAliveDuration + } + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { this.dispatcherExecutorService = dispatcherExecutorService } @@ -240,6 +266,22 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien .apply { dispatcherExecutorService?.let { dispatcher(Dispatcher(it)) } + val maxIdleConnections = maxIdleConnections + val keepAliveDuration = keepAliveDuration + if (maxIdleConnections != null && keepAliveDuration != null) { + connectionPool( + ConnectionPool( + maxIdleConnections, + keepAliveDuration.toNanos(), + TimeUnit.NANOSECONDS, + ) + ) + } else { + check((maxIdleConnections != null) == (keepAliveDuration != null)) { + "Both or none of `maxIdleConnections` and `keepAliveDuration` must be set, but only one was set" + } + } + val sslSocketFactory = sslSocketFactory val trustManager = trustManager if (sslSocketFactory != null && trustManager != null) { From 2720979743e942537ebb7314e83b8f64bc8e3455 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 06:38:50 +0000 Subject: [PATCH 21/63] chore(internal): remove mock server code --- .../com/blooio/api/TestServerExtension.kt | 49 ------------------- .../services/async/BatchServiceAsyncTest.kt | 27 ++-------- .../services/async/ContactServiceAsyncTest.kt | 9 +--- .../api/services/async/MeServiceAsyncTest.kt | 9 +--- .../services/async/MessageServiceAsyncTest.kt | 27 ++-------- .../async/config/WebhookServiceAsyncTest.kt | 15 +----- .../api/services/blocking/BatchServiceTest.kt | 27 ++-------- .../services/blocking/ContactServiceTest.kt | 9 +--- .../api/services/blocking/MeServiceTest.kt | 9 +--- .../services/blocking/MessageServiceTest.kt | 27 ++-------- .../blocking/config/WebhookServiceTest.kt | 15 +----- scripts/mock | 41 ---------------- scripts/test | 46 ----------------- 13 files changed, 24 insertions(+), 286 deletions(-) delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/TestServerExtension.kt delete mode 100755 scripts/mock diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/TestServerExtension.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/TestServerExtension.kt deleted file mode 100644 index 240b2e0..0000000 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/TestServerExtension.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.blooio.api - -import java.lang.RuntimeException -import java.net.URL -import org.junit.jupiter.api.extension.BeforeAllCallback -import org.junit.jupiter.api.extension.ConditionEvaluationResult -import org.junit.jupiter.api.extension.ExecutionCondition -import org.junit.jupiter.api.extension.ExtensionContext - -class TestServerExtension : BeforeAllCallback, ExecutionCondition { - - override fun beforeAll(context: ExtensionContext?) { - try { - URL(BASE_URL).openConnection().connect() - } catch (e: Exception) { - throw RuntimeException( - """ - The test suite will not run without a mock server running against your OpenAPI spec. - - You can set the environment variable `SKIP_MOCK_TESTS` to `true` to skip running any tests - that require the mock server. - - To fix run `./scripts/mock` in a separate terminal. - """ - .trimIndent(), - e, - ) - } - } - - override fun evaluateExecutionCondition(context: ExtensionContext): ConditionEvaluationResult { - return if (System.getenv(SKIP_TESTS_ENV).toBoolean()) { - ConditionEvaluationResult.disabled( - "Environment variable $SKIP_TESTS_ENV is set to true" - ) - } else { - ConditionEvaluationResult.enabled( - "Environment variable $SKIP_TESTS_ENV is not set to true" - ) - } - } - - companion object { - - val BASE_URL = System.getenv("TEST_API_BASE_URL") ?: "http://localhost:4010" - - const val SKIP_TESTS_ENV: String = "SKIP_MOCK_TESTS" - } -} diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/BatchServiceAsyncTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/BatchServiceAsyncTest.kt index 25bef59..f71204f 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/BatchServiceAsyncTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/BatchServiceAsyncTest.kt @@ -2,23 +2,16 @@ package com.blooio.api.services.async -import com.blooio.api.TestServerExtension import com.blooio.api.client.okhttp.BlooioOkHttpClientAsync import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class BatchServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun create() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val batchServiceAsync = client.batches() val future = batchServiceAsync.create() @@ -29,11 +22,7 @@ internal class BatchServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun retrieve() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val batchServiceAsync = client.batches() val future = batchServiceAsync.retrieve("batchId") @@ -44,11 +33,7 @@ internal class BatchServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun listMessages() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val batchServiceAsync = client.batches() val future = batchServiceAsync.listMessages("batchId") @@ -59,11 +44,7 @@ internal class BatchServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun retrieveStatus() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val batchServiceAsync = client.batches() val future = batchServiceAsync.retrieveStatus("batchId") diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/ContactServiceAsyncTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/ContactServiceAsyncTest.kt index 91bdb19..ebf5ff2 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/ContactServiceAsyncTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/ContactServiceAsyncTest.kt @@ -2,23 +2,16 @@ package com.blooio.api.services.async -import com.blooio.api.TestServerExtension import com.blooio.api.client.okhttp.BlooioOkHttpClientAsync import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class ContactServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun checkCapabilities() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val contactServiceAsync = client.contacts() val responseFuture = contactServiceAsync.checkCapabilities("contact") diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MeServiceAsyncTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MeServiceAsyncTest.kt index 4e391ee..77b2fea 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MeServiceAsyncTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MeServiceAsyncTest.kt @@ -2,23 +2,16 @@ package com.blooio.api.services.async -import com.blooio.api.TestServerExtension import com.blooio.api.client.okhttp.BlooioOkHttpClientAsync import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class MeServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun retrieve() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val meServiceAsync = client.me() val meFuture = meServiceAsync.retrieve() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MessageServiceAsyncTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MessageServiceAsyncTest.kt index 88d904c..0210e70 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MessageServiceAsyncTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MessageServiceAsyncTest.kt @@ -2,25 +2,18 @@ package com.blooio.api.services.async -import com.blooio.api.TestServerExtension import com.blooio.api.client.okhttp.BlooioOkHttpClientAsync import com.blooio.api.core.JsonValue import com.blooio.api.models.messages.MessageSendParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class MessageServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun retrieve() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val messageServiceAsync = client.messages() val messageFuture = messageServiceAsync.retrieve("messageId") @@ -32,11 +25,7 @@ internal class MessageServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun cancel() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val messageServiceAsync = client.messages() val responseFuture = messageServiceAsync.cancel("messageId") @@ -48,11 +37,7 @@ internal class MessageServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun getStatus() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val messageServiceAsync = client.messages() val responseFuture = messageServiceAsync.getStatus("messageId") @@ -64,11 +49,7 @@ internal class MessageServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun send() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val messageServiceAsync = client.messages() val responseFuture = diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncTest.kt index b639375..b29c278 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncTest.kt @@ -2,24 +2,17 @@ package com.blooio.api.services.async.config -import com.blooio.api.TestServerExtension import com.blooio.api.client.okhttp.BlooioOkHttpClientAsync import com.blooio.api.models.config.webhook.WebhookUpdateParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class WebhookServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun retrieve() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val webhookServiceAsync = client.config().webhook() val webhookFuture = webhookServiceAsync.retrieve() @@ -31,11 +24,7 @@ internal class WebhookServiceAsyncTest { @Disabled("Prism tests are disabled") @Test fun update() { - val client = - BlooioOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() val webhookServiceAsync = client.config().webhook() val webhookFuture = diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/BatchServiceTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/BatchServiceTest.kt index ea136e9..5bd76ac 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/BatchServiceTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/BatchServiceTest.kt @@ -2,23 +2,16 @@ package com.blooio.api.services.blocking -import com.blooio.api.TestServerExtension import com.blooio.api.client.okhttp.BlooioOkHttpClient import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class BatchServiceTest { @Disabled("Prism tests are disabled") @Test fun create() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val batchService = client.batches() batchService.create() @@ -27,11 +20,7 @@ internal class BatchServiceTest { @Disabled("Prism tests are disabled") @Test fun retrieve() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val batchService = client.batches() batchService.retrieve("batchId") @@ -40,11 +29,7 @@ internal class BatchServiceTest { @Disabled("Prism tests are disabled") @Test fun listMessages() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val batchService = client.batches() batchService.listMessages("batchId") @@ -53,11 +38,7 @@ internal class BatchServiceTest { @Disabled("Prism tests are disabled") @Test fun retrieveStatus() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val batchService = client.batches() batchService.retrieveStatus("batchId") diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/ContactServiceTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/ContactServiceTest.kt index 1c5eea4..d3a0a4c 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/ContactServiceTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/ContactServiceTest.kt @@ -2,23 +2,16 @@ package com.blooio.api.services.blocking -import com.blooio.api.TestServerExtension import com.blooio.api.client.okhttp.BlooioOkHttpClient import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class ContactServiceTest { @Disabled("Prism tests are disabled") @Test fun checkCapabilities() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val contactService = client.contacts() val response = contactService.checkCapabilities("contact") diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MeServiceTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MeServiceTest.kt index c41e96c..383b436 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MeServiceTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MeServiceTest.kt @@ -2,23 +2,16 @@ package com.blooio.api.services.blocking -import com.blooio.api.TestServerExtension import com.blooio.api.client.okhttp.BlooioOkHttpClient import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class MeServiceTest { @Disabled("Prism tests are disabled") @Test fun retrieve() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val meService = client.me() val me = meService.retrieve() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MessageServiceTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MessageServiceTest.kt index ae6efb6..734072a 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MessageServiceTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MessageServiceTest.kt @@ -2,25 +2,18 @@ package com.blooio.api.services.blocking -import com.blooio.api.TestServerExtension import com.blooio.api.client.okhttp.BlooioOkHttpClient import com.blooio.api.core.JsonValue import com.blooio.api.models.messages.MessageSendParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class MessageServiceTest { @Disabled("Prism tests are disabled") @Test fun retrieve() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val messageService = client.messages() val message = messageService.retrieve("messageId") @@ -31,11 +24,7 @@ internal class MessageServiceTest { @Disabled("Prism tests are disabled") @Test fun cancel() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val messageService = client.messages() val response = messageService.cancel("messageId") @@ -46,11 +35,7 @@ internal class MessageServiceTest { @Disabled("Prism tests are disabled") @Test fun getStatus() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val messageService = client.messages() val response = messageService.getStatus("messageId") @@ -61,11 +46,7 @@ internal class MessageServiceTest { @Disabled("Prism tests are disabled") @Test fun send() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val messageService = client.messages() val response = diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/config/WebhookServiceTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/config/WebhookServiceTest.kt index db48dbf..efad51d 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/config/WebhookServiceTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/config/WebhookServiceTest.kt @@ -2,24 +2,17 @@ package com.blooio.api.services.blocking.config -import com.blooio.api.TestServerExtension import com.blooio.api.client.okhttp.BlooioOkHttpClient import com.blooio.api.models.config.webhook.WebhookUpdateParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class WebhookServiceTest { @Disabled("Prism tests are disabled") @Test fun retrieve() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val webhookService = client.config().webhook() val webhook = webhookService.retrieve() @@ -30,11 +23,7 @@ internal class WebhookServiceTest { @Disabled("Prism tests are disabled") @Test fun update() { - val client = - BlooioOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() + val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() val webhookService = client.config().webhook() val webhook = diff --git a/scripts/mock b/scripts/mock deleted file mode 100755 index 0b28f6e..0000000 --- a/scripts/mock +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd "$(dirname "$0")/.." - -if [[ -n "$1" && "$1" != '--'* ]]; then - URL="$1" - shift -else - URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" -fi - -# Check if the URL is empty -if [ -z "$URL" ]; then - echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" - exit 1 -fi - -echo "==> Starting mock server with URL ${URL}" - -# Run prism mock on the given spec -if [ "$1" == "--daemon" ]; then - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & - - # Wait for server to come online - echo -n "Waiting for server" - while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do - echo -n "." - sleep 0.1 - done - - if grep -q "✖ fatal" ".prism.log"; then - cat .prism.log - exit 1 - fi - - echo -else - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" -fi diff --git a/scripts/test b/scripts/test index 047bc1d..904aea6 100755 --- a/scripts/test +++ b/scripts/test @@ -4,53 +4,7 @@ set -e cd "$(dirname "$0")/.." -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[0;33m' -NC='\033[0m' # No Color -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 -} - -kill_server_on_port() { - pids=$(lsof -t -i tcp:"$1" || echo "") - if [ "$pids" != "" ]; then - kill "$pids" - echo "Stopped $pids." - fi -} - -function is_overriding_api_base_url() { - [ -n "$TEST_API_BASE_URL" ] -} - -if ! is_overriding_api_base_url && ! prism_is_running ; then - # When we exit this script, make sure to kill the background mock server process - trap 'kill_server_on_port 4010' EXIT - - # Start the dev server - ./scripts/mock --daemon -fi - -if is_overriding_api_base_url ; then - echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" - echo -elif ! prism_is_running ; then - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" - echo -e "running against your OpenAPI spec." - echo - echo -e "To run the server, pass in the path or url of your OpenAPI" - echo -e "spec to the prism command:" - echo - echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" - echo - - exit 1 -else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" - echo -fi echo "==> Running tests" ./gradlew test "$@" From 00e0cf57e1fb18ddcc685aeea1cce58ac6decf0c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 06:39:30 +0000 Subject: [PATCH 22/63] chore: update mock server docs --- .../kotlin/com/blooio/api/services/ServiceParamsTest.kt | 2 +- .../blooio/api/services/async/BatchServiceAsyncTest.kt | 8 ++++---- .../blooio/api/services/async/ContactServiceAsyncTest.kt | 2 +- .../com/blooio/api/services/async/MeServiceAsyncTest.kt | 2 +- .../blooio/api/services/async/MessageServiceAsyncTest.kt | 8 ++++---- .../api/services/async/config/WebhookServiceAsyncTest.kt | 4 ++-- .../com/blooio/api/services/blocking/BatchServiceTest.kt | 8 ++++---- .../blooio/api/services/blocking/ContactServiceTest.kt | 2 +- .../com/blooio/api/services/blocking/MeServiceTest.kt | 2 +- .../blooio/api/services/blocking/MessageServiceTest.kt | 8 ++++---- .../api/services/blocking/config/WebhookServiceTest.kt | 4 ++-- 11 files changed, 25 insertions(+), 25 deletions(-) diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/ServiceParamsTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/ServiceParamsTest.kt index ac6f723..5964716 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/ServiceParamsTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/ServiceParamsTest.kt @@ -34,7 +34,7 @@ internal class ServiceParamsTest { .build() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun retrieve() { val meService = client.me() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/BatchServiceAsyncTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/BatchServiceAsyncTest.kt index f71204f..4c2ef1e 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/BatchServiceAsyncTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/BatchServiceAsyncTest.kt @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test internal class BatchServiceAsyncTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun create() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() @@ -19,7 +19,7 @@ internal class BatchServiceAsyncTest { val response = future.get() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun retrieve() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() @@ -30,7 +30,7 @@ internal class BatchServiceAsyncTest { val response = future.get() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun listMessages() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() @@ -41,7 +41,7 @@ internal class BatchServiceAsyncTest { val response = future.get() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun retrieveStatus() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/ContactServiceAsyncTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/ContactServiceAsyncTest.kt index ebf5ff2..514c6b7 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/ContactServiceAsyncTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/ContactServiceAsyncTest.kt @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test internal class ContactServiceAsyncTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun checkCapabilities() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MeServiceAsyncTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MeServiceAsyncTest.kt index 77b2fea..4ccc4ef 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MeServiceAsyncTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MeServiceAsyncTest.kt @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test internal class MeServiceAsyncTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun retrieve() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MessageServiceAsyncTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MessageServiceAsyncTest.kt index 0210e70..a738bdc 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MessageServiceAsyncTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MessageServiceAsyncTest.kt @@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test internal class MessageServiceAsyncTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun retrieve() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() @@ -22,7 +22,7 @@ internal class MessageServiceAsyncTest { message.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun cancel() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() @@ -34,7 +34,7 @@ internal class MessageServiceAsyncTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun getStatus() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() @@ -46,7 +46,7 @@ internal class MessageServiceAsyncTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun send() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncTest.kt index b29c278..c05c0a4 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncTest.kt @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test internal class WebhookServiceAsyncTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun retrieve() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() @@ -21,7 +21,7 @@ internal class WebhookServiceAsyncTest { webhook.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun update() { val client = BlooioOkHttpClientAsync.builder().apiKey("My API Key").build() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/BatchServiceTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/BatchServiceTest.kt index 5bd76ac..c85ee5d 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/BatchServiceTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/BatchServiceTest.kt @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test internal class BatchServiceTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun create() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() @@ -17,7 +17,7 @@ internal class BatchServiceTest { batchService.create() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun retrieve() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() @@ -26,7 +26,7 @@ internal class BatchServiceTest { batchService.retrieve("batchId") } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun listMessages() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() @@ -35,7 +35,7 @@ internal class BatchServiceTest { batchService.listMessages("batchId") } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun retrieveStatus() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/ContactServiceTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/ContactServiceTest.kt index d3a0a4c..4d44676 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/ContactServiceTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/ContactServiceTest.kt @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test internal class ContactServiceTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun checkCapabilities() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MeServiceTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MeServiceTest.kt index 383b436..822b9e8 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MeServiceTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MeServiceTest.kt @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test internal class MeServiceTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun retrieve() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MessageServiceTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MessageServiceTest.kt index 734072a..04c796e 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MessageServiceTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MessageServiceTest.kt @@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test internal class MessageServiceTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun retrieve() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() @@ -21,7 +21,7 @@ internal class MessageServiceTest { message.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun cancel() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() @@ -32,7 +32,7 @@ internal class MessageServiceTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun getStatus() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() @@ -43,7 +43,7 @@ internal class MessageServiceTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun send() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/config/WebhookServiceTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/config/WebhookServiceTest.kt index efad51d..aae8744 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/config/WebhookServiceTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/config/WebhookServiceTest.kt @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test internal class WebhookServiceTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun retrieve() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() @@ -20,7 +20,7 @@ internal class WebhookServiceTest { webhook.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun update() { val client = BlooioOkHttpClient.builder().apiKey("My API Key").build() From d9397764180aeb78502302531fbc19c928fa1ab5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 07:01:28 +0000 Subject: [PATCH 23/63] chore(internal): codegen related update --- blooio-java-core/build.gradle.kts | 2 - .../kotlin/com/blooio/api/core/Properties.kt | 6 +- .../blooio/api/core/http/HttpRequestBodies.kt | 295 +++++-- .../api/core/http/HttpRequestBodiesTest.kt | 729 ++++++++++++++++++ 4 files changed, 949 insertions(+), 83 deletions(-) create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/core/http/HttpRequestBodiesTest.kt diff --git a/blooio-java-core/build.gradle.kts b/blooio-java-core/build.gradle.kts index f647be8..18b3914 100644 --- a/blooio-java-core/build.gradle.kts +++ b/blooio-java-core/build.gradle.kts @@ -27,8 +27,6 @@ dependencies { implementation("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.18.2") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.2") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.2") - implementation("org.apache.httpcomponents.core5:httpcore5:5.2.4") - implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1") testImplementation(kotlin("test")) testImplementation(project(":blooio-java-client-okhttp")) diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/Properties.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/Properties.kt index 5aa1fbd..60ca187 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/Properties.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/Properties.kt @@ -34,9 +34,9 @@ fun getOsName(): String { } } -fun getOsVersion(): String = System.getProperty("os.version", "unknown") +fun getOsVersion(): String = System.getProperty("os.version", "unknown") ?: "unknown" fun getPackageVersion(): String = - BlooioClient::class.java.`package`.implementationVersion ?: "unknown" + BlooioClient::class.java.`package`?.implementationVersion ?: "unknown" -fun getJavaVersion(): String = System.getProperty("java.version", "unknown") +fun getJavaVersion(): String = System.getProperty("java.version", "unknown") ?: "unknown" diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/HttpRequestBodies.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/HttpRequestBodies.kt index c2c707d..6febc5e 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/HttpRequestBodies.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/HttpRequestBodies.kt @@ -5,16 +5,16 @@ package com.blooio.api.core.http import com.blooio.api.core.MultipartField +import com.blooio.api.core.toImmutable import com.blooio.api.errors.BlooioInvalidDataException import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.databind.node.JsonNodeType +import java.io.ByteArrayInputStream import java.io.InputStream import java.io.OutputStream +import java.util.UUID import kotlin.jvm.optionals.getOrNull -import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder -import org.apache.hc.core5.http.ContentType -import org.apache.hc.core5.http.HttpEntity @JvmSynthetic internal inline fun json(jsonMapper: JsonMapper, value: T): HttpRequestBody = @@ -37,92 +37,231 @@ internal fun multipartFormData( jsonMapper: JsonMapper, fields: Map>, ): HttpRequestBody = - object : HttpRequestBody { - private val entity: HttpEntity by lazy { - MultipartEntityBuilder.create() - .apply { - fields.forEach { (name, field) -> - val knownValue = field.value.asKnown().getOrNull() - val parts = - if (knownValue is InputStream) { - // Read directly from the `InputStream` instead of reading it all - // into memory due to the `jsonMapper` serialization below. - sequenceOf(name to knownValue) - } else { - val node = jsonMapper.valueToTree(field.value) - serializePart(name, node) + MultipartBody.Builder() + .apply { + fields.forEach { (name, field) -> + val knownValue = field.value.asKnown().getOrNull() + val parts = + if (knownValue is InputStream) { + // Read directly from the `InputStream` instead of reading it all + // into memory due to the `jsonMapper` serialization below. + sequenceOf(name to knownValue) + } else { + val node = jsonMapper.valueToTree(field.value) + serializePart(name, node) + } + + parts.forEach { (name, bytes) -> + val partBody = + if (bytes is ByteArrayInputStream) { + val byteArray = bytes.readBytes() + + object : HttpRequestBody { + + override fun writeTo(outputStream: OutputStream) { + outputStream.write(byteArray) + } + + override fun contentType(): String = field.contentType + + override fun contentLength(): Long = byteArray.size.toLong() + + override fun repeatable(): Boolean = true + + override fun close() {} } + } else { + object : HttpRequestBody { + + override fun writeTo(outputStream: OutputStream) { + bytes.copyTo(outputStream) + } + + override fun contentType(): String = field.contentType + + override fun contentLength(): Long = -1L - parts.forEach { (name, bytes) -> - addBinaryBody( - name, - bytes, - ContentType.parseLenient(field.contentType), - field.filename().getOrNull(), - ) + override fun repeatable(): Boolean = false + + override fun close() = bytes.close() + } } - } + + addPart( + MultipartBody.Part.create( + name, + field.filename().getOrNull(), + field.contentType, + partBody, + ) + ) } - .build() + } } + .build() - private fun serializePart( - name: String, - node: JsonNode, - ): Sequence> = - when (node.nodeType) { - JsonNodeType.MISSING, - JsonNodeType.NULL -> emptySequence() - JsonNodeType.BINARY -> sequenceOf(name to node.binaryValue().inputStream()) - JsonNodeType.STRING -> sequenceOf(name to node.textValue().inputStream()) - JsonNodeType.BOOLEAN -> - sequenceOf(name to node.booleanValue().toString().inputStream()) - JsonNodeType.NUMBER -> - sequenceOf(name to node.numberValue().toString().inputStream()) - JsonNodeType.ARRAY -> - sequenceOf( - name to - node - .elements() - .asSequence() - .mapNotNull { element -> - when (element.nodeType) { - JsonNodeType.MISSING, - JsonNodeType.NULL -> null - JsonNodeType.STRING -> node.textValue() - JsonNodeType.BOOLEAN -> node.booleanValue().toString() - JsonNodeType.NUMBER -> node.numberValue().toString() - null, - JsonNodeType.BINARY, - JsonNodeType.ARRAY, - JsonNodeType.OBJECT, - JsonNodeType.POJO -> - throw BlooioInvalidDataException( - "Unexpected JsonNode type in array: ${node.nodeType}" - ) - } - } - .joinToString(",") - .inputStream() - ) - JsonNodeType.OBJECT -> - node.fields().asSequence().flatMap { (key, value) -> - serializePart("$name[$key]", value) - } - JsonNodeType.POJO, - null -> - throw BlooioInvalidDataException("Unexpected JsonNode type: ${node.nodeType}") +private fun serializePart(name: String, node: JsonNode): Sequence> = + when (node.nodeType) { + JsonNodeType.MISSING, + JsonNodeType.NULL -> emptySequence() + JsonNodeType.BINARY -> sequenceOf(name to node.binaryValue().inputStream()) + JsonNodeType.STRING -> sequenceOf(name to node.textValue().byteInputStream()) + JsonNodeType.BOOLEAN -> sequenceOf(name to node.booleanValue().toString().byteInputStream()) + JsonNodeType.NUMBER -> sequenceOf(name to node.numberValue().toString().byteInputStream()) + JsonNodeType.ARRAY -> + sequenceOf( + name to + node + .elements() + .asSequence() + .mapNotNull { element -> + when (element.nodeType) { + JsonNodeType.MISSING, + JsonNodeType.NULL -> null + JsonNodeType.STRING -> element.textValue() + JsonNodeType.BOOLEAN -> element.booleanValue().toString() + JsonNodeType.NUMBER -> element.numberValue().toString() + null, + JsonNodeType.BINARY, + JsonNodeType.ARRAY, + JsonNodeType.OBJECT, + JsonNodeType.POJO -> + throw BlooioInvalidDataException( + "Unexpected JsonNode type in array: ${element.nodeType}" + ) + } + } + .joinToString(",") + .byteInputStream() + ) + JsonNodeType.OBJECT -> + node.fields().asSequence().flatMap { (key, value) -> + serializePart("$name[$key]", value) + } + JsonNodeType.POJO, + null -> throw BlooioInvalidDataException("Unexpected JsonNode type: ${node.nodeType}") + } + +private class MultipartBody +private constructor(private val boundary: String, private val parts: List) : HttpRequestBody { + private val boundaryBytes: ByteArray = boundary.toByteArray() + private val contentType = "multipart/form-data; boundary=$boundary" + + // This must remain in sync with `contentLength`. + override fun writeTo(outputStream: OutputStream) { + parts.forEach { part -> + outputStream.write(DASHDASH) + outputStream.write(boundaryBytes) + outputStream.write(CRLF) + + outputStream.write(CONTENT_DISPOSITION) + outputStream.write(part.contentDisposition.toByteArray()) + outputStream.write(CRLF) + + outputStream.write(CONTENT_TYPE) + outputStream.write(part.contentType.toByteArray()) + outputStream.write(CRLF) + + outputStream.write(CRLF) + part.body.writeTo(outputStream) + outputStream.write(CRLF) + } + + outputStream.write(DASHDASH) + outputStream.write(boundaryBytes) + outputStream.write(DASHDASH) + outputStream.write(CRLF) + } + + override fun contentType(): String = contentType + + // This must remain in sync with `writeTo`. + override fun contentLength(): Long { + var byteCount = 0L + + parts.forEach { part -> + val contentLength = part.body.contentLength() + if (contentLength == -1L) { + return -1L } - private fun String.inputStream(): InputStream = toByteArray().inputStream() + byteCount += + DASHDASH.size + + boundaryBytes.size + + CRLF.size + + CONTENT_DISPOSITION.size + + part.contentDisposition.toByteArray().size + + CRLF.size + + CONTENT_TYPE.size + + part.contentType.toByteArray().size + + CRLF.size + + CRLF.size + + contentLength + + CRLF.size + } - override fun writeTo(outputStream: OutputStream) = entity.writeTo(outputStream) + byteCount += DASHDASH.size + boundaryBytes.size + DASHDASH.size + CRLF.size + return byteCount + } - override fun contentType(): String = entity.contentType + override fun repeatable(): Boolean = parts.all { it.body.repeatable() } - override fun contentLength(): Long = entity.contentLength + override fun close() { + parts.forEach { it.body.close() } + } - override fun repeatable(): Boolean = entity.isRepeatable + class Builder { + private val boundary = UUID.randomUUID().toString() + private val parts: MutableList = mutableListOf() - override fun close() = entity.close() + fun addPart(part: Part) = apply { parts.add(part) } + + fun build() = MultipartBody(boundary, parts.toImmutable()) + } + + class Part + private constructor( + val contentDisposition: String, + val contentType: String, + val body: HttpRequestBody, + ) { + companion object { + fun create( + name: String, + filename: String?, + contentType: String, + body: HttpRequestBody, + ): Part { + val disposition = buildString { + append("form-data; name=") + appendQuotedString(name) + if (filename != null) { + append("; filename=") + appendQuotedString(filename) + } + } + return Part(disposition, contentType, body) + } + } + } + + companion object { + private val CRLF = byteArrayOf('\r'.code.toByte(), '\n'.code.toByte()) + private val DASHDASH = byteArrayOf('-'.code.toByte(), '-'.code.toByte()) + private val CONTENT_DISPOSITION = "Content-Disposition: ".toByteArray() + private val CONTENT_TYPE = "Content-Type: ".toByteArray() + + private fun StringBuilder.appendQuotedString(key: String) { + append('"') + for (ch in key) { + when (ch) { + '\n' -> append("%0A") + '\r' -> append("%0D") + '"' -> append("%22") + else -> append(ch) + } + } + append('"') + } } +} diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/core/http/HttpRequestBodiesTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/core/http/HttpRequestBodiesTest.kt new file mode 100644 index 0000000..ac774a0 --- /dev/null +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/core/http/HttpRequestBodiesTest.kt @@ -0,0 +1,729 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.core.http + +import com.blooio.api.core.MultipartField +import com.blooio.api.core.jsonMapper +import java.io.ByteArrayOutputStream +import java.io.InputStream +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class HttpRequestBodiesTest { + + @Test + fun multipartFormData_serializesFieldWithFilename() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "file" to + MultipartField.builder() + .value("hello") + .filename("hello.txt") + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(output.size().toLong()).isEqualTo(body.contentLength()) + val boundary = body.contentType()!!.substringAfter("multipart/form-data; boundary=") + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="file"; filename="hello.txt" + |Content-Type: text/plain + | + |hello + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesFieldWithoutFilename() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "field" to + MultipartField.builder() + .value("value") + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(output.size().toLong()).isEqualTo(body.contentLength()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="field" + |Content-Type: text/plain + | + |value + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesInputStream() { + // Use `.buffered()` to get a non-ByteArrayInputStream, which hits the non-repeatable code + // path. + val inputStream = "stream content".byteInputStream().buffered() + val body = + multipartFormData( + jsonMapper(), + mapOf( + "data" to + MultipartField.builder() + .value(inputStream) + .contentType("application/octet-stream") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isFalse() + assertThat(body.contentLength()).isEqualTo(-1L) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="data" + |Content-Type: application/octet-stream + | + |stream content + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesByteArray() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "binary" to + MultipartField.builder() + .value("abc".toByteArray()) + .contentType("application/octet-stream") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="binary" + |Content-Type: application/octet-stream + | + |abc + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesBooleanValue() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "flag" to + MultipartField.builder() + .value(true) + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="flag" + |Content-Type: text/plain + | + |true + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesNumberValue() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "count" to + MultipartField.builder().value(42).contentType("text/plain").build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="count" + |Content-Type: text/plain + | + |42 + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesNullValueAsNoParts() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "present" to + MultipartField.builder() + .value("yes") + .contentType("text/plain") + .build(), + "absent" to + MultipartField.builder() + .value(null as String?) + .contentType("text/plain") + .build(), + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="present" + |Content-Type: text/plain + | + |yes + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesArray() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "items" to + MultipartField.builder>() + .value(listOf("alpha", "beta", "gamma")) + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="items" + |Content-Type: text/plain + | + |alpha,beta,gamma + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesObjectAsNestedParts() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "meta" to + MultipartField.builder>() + .value(mapOf("key1" to "val1", "key2" to "val2")) + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="meta[key1]" + |Content-Type: text/plain + | + |val1 + |--$boundary + |Content-Disposition: form-data; name="meta[key2]" + |Content-Type: text/plain + | + |val2 + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesMultipleFields() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "name" to + MultipartField.builder() + .value("Alice") + .contentType("text/plain") + .build(), + "age" to + MultipartField.builder().value(30).contentType("text/plain").build(), + "file" to + MultipartField.builder() + .value("file contents") + .filename("doc.txt") + .contentType("text/plain") + .build(), + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="name" + |Content-Type: text/plain + | + |Alice + |--$boundary + |Content-Disposition: form-data; name="age" + |Content-Type: text/plain + | + |30 + |--$boundary + |Content-Disposition: form-data; name="file"; filename="doc.txt" + |Content-Type: text/plain + | + |file contents + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_quotesSpecialCharactersInNameAndFilename() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "field\nname" to + MultipartField.builder() + .value("value") + .filename("file\r\"name.txt") + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="field%0Aname"; filename="file%0D%22name.txt" + |Content-Type: text/plain + | + |value + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_writeIsRepeatable() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "field" to + MultipartField.builder() + .value("repeatable") + .contentType("text/plain") + .build() + ), + ) + + val output1 = ByteArrayOutputStream() + body.writeTo(output1) + val output2 = ByteArrayOutputStream() + body.writeTo(output2) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output1.size().toLong()) + val boundary = boundary(body) + val expected = + """ + |--$boundary + |Content-Disposition: form-data; name="field" + |Content-Type: text/plain + | + |repeatable + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + assertThat(output1.toString("UTF-8")).isEqualTo(expected) + assertThat(output2.toString("UTF-8")).isEqualTo(expected) + } + + @Test + fun multipartFormData_serializesByteArrayInputStream() { + // ByteArrayInputStream is specifically handled as repeatable with known content length. + val inputStream = "byte array stream".byteInputStream() + val body = + multipartFormData( + jsonMapper(), + mapOf( + "data" to + MultipartField.builder() + .value(inputStream) + .contentType("application/octet-stream") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="data" + |Content-Type: application/octet-stream + | + |byte array stream + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesInputStreamWithFilename() { + // Use `.buffered()` to get a non-ByteArrayInputStream, which hits the non-repeatable code + // path. + val inputStream = "file data".byteInputStream().buffered() + val body = + multipartFormData( + jsonMapper(), + mapOf( + "upload" to + MultipartField.builder() + .value(inputStream) + .filename("upload.bin") + .contentType("application/octet-stream") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isFalse() + assertThat(body.contentLength()).isEqualTo(-1L) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="upload"; filename="upload.bin" + |Content-Type: application/octet-stream + | + |file data + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesNestedArrayInObject() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "data" to + MultipartField.builder>>() + .value(mapOf("tags" to listOf("a", "b"))) + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="data[tags]" + |Content-Type: text/plain + | + |a,b + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_contentLengthIsUnknownWhenInputStreamPresent() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "text" to + MultipartField.builder() + .value("hello") + .contentType("text/plain") + .build(), + "stream" to + MultipartField.builder() + // Use `.buffered()` to get a non-ByteArrayInputStream, which hits the + // non-repeatable code path. + .value("data".byteInputStream().buffered()) + .contentType("application/octet-stream") + .build(), + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isFalse() + assertThat(body.contentLength()).isEqualTo(-1L) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="text" + |Content-Type: text/plain + | + |hello + |--$boundary + |Content-Disposition: form-data; name="stream" + |Content-Type: application/octet-stream + | + |data + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesEmptyArray() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "required" to + MultipartField.builder() + .value("present") + .contentType("text/plain") + .build(), + "items" to + MultipartField.builder>() + .value(emptyList()) + .contentType("text/plain") + .build(), + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="required" + |Content-Type: text/plain + | + |present + |--$boundary + |Content-Disposition: form-data; name="items" + |Content-Type: text/plain + | + | + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesEmptyObject() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "required" to + MultipartField.builder() + .value("present") + .contentType("text/plain") + .build(), + "meta" to + MultipartField.builder>() + .value(emptyMap()) + .contentType("text/plain") + .build(), + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="required" + |Content-Type: text/plain + | + |present + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + private fun boundary(body: HttpRequestBody): String = + body.contentType()!!.substringAfter("multipart/form-data; boundary=") +} From 58fcb730f98e0c1c1d8006b0aeb96f0aeb678a8b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 06:50:35 +0000 Subject: [PATCH 24/63] chore(internal): codegen related update --- .../com/blooio/api/core/http/RetryingHttpClient.kt | 2 ++ .../blooio/api/core/http/RetryingHttpClientTest.kt | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt index f261e5f..ed77d2a 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt @@ -1,3 +1,5 @@ +// File generated from our OpenAPI spec by Stainless. + package com.blooio.api.core.http import com.blooio.api.core.DefaultSleeper diff --git a/blooio-java-core/src/test/kotlin/com/blooio/api/core/http/RetryingHttpClientTest.kt b/blooio-java-core/src/test/kotlin/com/blooio/api/core/http/RetryingHttpClientTest.kt index d31b725..4b595df 100644 --- a/blooio-java-core/src/test/kotlin/com/blooio/api/core/http/RetryingHttpClientTest.kt +++ b/blooio-java-core/src/test/kotlin/com/blooio/api/core/http/RetryingHttpClientTest.kt @@ -1,10 +1,21 @@ +// File generated from our OpenAPI spec by Stainless. + package com.blooio.api.core.http import com.blooio.api.client.okhttp.OkHttpClient import com.blooio.api.core.RequestOptions import com.blooio.api.core.Sleeper import com.blooio.api.errors.BlooioRetryableException -import com.github.tomakehurst.wiremock.client.WireMock.* +import com.github.tomakehurst.wiremock.client.WireMock.equalTo +import com.github.tomakehurst.wiremock.client.WireMock.matching +import com.github.tomakehurst.wiremock.client.WireMock.ok +import com.github.tomakehurst.wiremock.client.WireMock.post +import com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor +import com.github.tomakehurst.wiremock.client.WireMock.resetAllScenarios +import com.github.tomakehurst.wiremock.client.WireMock.serviceUnavailable +import com.github.tomakehurst.wiremock.client.WireMock.stubFor +import com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo +import com.github.tomakehurst.wiremock.client.WireMock.verify import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest import com.github.tomakehurst.wiremock.stubbing.Scenario From ccf03561744755a1bd800449143bc61b847b17ab Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 12:30:45 +0000 Subject: [PATCH 25/63] chore(internal): codegen related update --- .../src/main/kotlin/com/blooio/api/client/BlooioClient.kt | 8 ++++++++ .../kotlin/com/blooio/api/client/BlooioClientAsync.kt | 8 ++++++++ .../kotlin/com/blooio/api/client/BlooioClientAsyncImpl.kt | 8 ++++++++ .../main/kotlin/com/blooio/api/client/BlooioClientImpl.kt | 8 ++++++++ .../com/blooio/api/services/async/BatchServiceAsync.kt | 1 + .../blooio/api/services/async/BatchServiceAsyncImpl.kt | 1 + .../com/blooio/api/services/async/ConfigServiceAsync.kt | 2 ++ .../blooio/api/services/async/ConfigServiceAsyncImpl.kt | 2 ++ .../com/blooio/api/services/async/ContactServiceAsync.kt | 1 + .../blooio/api/services/async/ContactServiceAsyncImpl.kt | 1 + .../com/blooio/api/services/async/MeServiceAsync.kt | 1 + .../com/blooio/api/services/async/MeServiceAsyncImpl.kt | 1 + .../com/blooio/api/services/async/MessageServiceAsync.kt | 1 + .../blooio/api/services/async/MessageServiceAsyncImpl.kt | 1 + .../api/services/async/config/WebhookServiceAsync.kt | 1 + .../api/services/async/config/WebhookServiceAsyncImpl.kt | 1 + .../com/blooio/api/services/blocking/BatchService.kt | 1 + .../com/blooio/api/services/blocking/BatchServiceImpl.kt | 1 + .../com/blooio/api/services/blocking/ConfigService.kt | 2 ++ .../com/blooio/api/services/blocking/ConfigServiceImpl.kt | 2 ++ .../com/blooio/api/services/blocking/ContactService.kt | 1 + .../blooio/api/services/blocking/ContactServiceImpl.kt | 1 + .../kotlin/com/blooio/api/services/blocking/MeService.kt | 1 + .../com/blooio/api/services/blocking/MeServiceImpl.kt | 1 + .../com/blooio/api/services/blocking/MessageService.kt | 1 + .../blooio/api/services/blocking/MessageServiceImpl.kt | 1 + .../blooio/api/services/blocking/config/WebhookService.kt | 1 + .../api/services/blocking/config/WebhookServiceImpl.kt | 1 + 28 files changed, 60 insertions(+) diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClient.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClient.kt index 77dd88d..934a821 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClient.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClient.kt @@ -46,14 +46,18 @@ interface BlooioClient { */ fun withOptions(modifier: Consumer): BlooioClient + /** Account and API key information */ fun me(): MeService + /** Contact-related operations */ fun contacts(): ContactService + /** Send and manage individual messages */ fun messages(): MessageService fun config(): ConfigService + /** Bulk/batch operations (stubbed) */ fun batches(): BatchService /** @@ -79,14 +83,18 @@ interface BlooioClient { */ fun withOptions(modifier: Consumer): BlooioClient.WithRawResponse + /** Account and API key information */ fun me(): MeService.WithRawResponse + /** Contact-related operations */ fun contacts(): ContactService.WithRawResponse + /** Send and manage individual messages */ fun messages(): MessageService.WithRawResponse fun config(): ConfigService.WithRawResponse + /** Bulk/batch operations (stubbed) */ fun batches(): BatchService.WithRawResponse } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsync.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsync.kt index 83256cc..c205669 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsync.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsync.kt @@ -46,14 +46,18 @@ interface BlooioClientAsync { */ fun withOptions(modifier: Consumer): BlooioClientAsync + /** Account and API key information */ fun me(): MeServiceAsync + /** Contact-related operations */ fun contacts(): ContactServiceAsync + /** Send and manage individual messages */ fun messages(): MessageServiceAsync fun config(): ConfigServiceAsync + /** Bulk/batch operations (stubbed) */ fun batches(): BatchServiceAsync /** @@ -81,14 +85,18 @@ interface BlooioClientAsync { modifier: Consumer ): BlooioClientAsync.WithRawResponse + /** Account and API key information */ fun me(): MeServiceAsync.WithRawResponse + /** Contact-related operations */ fun contacts(): ContactServiceAsync.WithRawResponse + /** Send and manage individual messages */ fun messages(): MessageServiceAsync.WithRawResponse fun config(): ConfigServiceAsync.WithRawResponse + /** Bulk/batch operations (stubbed) */ fun batches(): BatchServiceAsync.WithRawResponse } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsyncImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsyncImpl.kt index 764d2b2..fc2615a 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsyncImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsyncImpl.kt @@ -58,14 +58,18 @@ class BlooioClientAsyncImpl(private val clientOptions: ClientOptions) : BlooioCl override fun withOptions(modifier: Consumer): BlooioClientAsync = BlooioClientAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** Account and API key information */ override fun me(): MeServiceAsync = me + /** Contact-related operations */ override fun contacts(): ContactServiceAsync = contacts + /** Send and manage individual messages */ override fun messages(): MessageServiceAsync = messages override fun config(): ConfigServiceAsync = config + /** Bulk/batch operations (stubbed) */ override fun batches(): BatchServiceAsync = batches override fun close() = clientOptions.close() @@ -100,14 +104,18 @@ class BlooioClientAsyncImpl(private val clientOptions: ClientOptions) : BlooioCl clientOptions.toBuilder().apply(modifier::accept).build() ) + /** Account and API key information */ override fun me(): MeServiceAsync.WithRawResponse = me + /** Contact-related operations */ override fun contacts(): ContactServiceAsync.WithRawResponse = contacts + /** Send and manage individual messages */ override fun messages(): MessageServiceAsync.WithRawResponse = messages override fun config(): ConfigServiceAsync.WithRawResponse = config + /** Bulk/batch operations (stubbed) */ override fun batches(): BatchServiceAsync.WithRawResponse = batches } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientImpl.kt index 50431c9..ff6d1b3 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientImpl.kt @@ -50,14 +50,18 @@ class BlooioClientImpl(private val clientOptions: ClientOptions) : BlooioClient override fun withOptions(modifier: Consumer): BlooioClient = BlooioClientImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** Account and API key information */ override fun me(): MeService = me + /** Contact-related operations */ override fun contacts(): ContactService = contacts + /** Send and manage individual messages */ override fun messages(): MessageService = messages override fun config(): ConfigService = config + /** Bulk/batch operations (stubbed) */ override fun batches(): BatchService = batches override fun close() = clientOptions.close() @@ -92,14 +96,18 @@ class BlooioClientImpl(private val clientOptions: ClientOptions) : BlooioClient clientOptions.toBuilder().apply(modifier::accept).build() ) + /** Account and API key information */ override fun me(): MeService.WithRawResponse = me + /** Contact-related operations */ override fun contacts(): ContactService.WithRawResponse = contacts + /** Send and manage individual messages */ override fun messages(): MessageService.WithRawResponse = messages override fun config(): ConfigService.WithRawResponse = config + /** Bulk/batch operations (stubbed) */ override fun batches(): BatchService.WithRawResponse = batches } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/BatchServiceAsync.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/BatchServiceAsync.kt index d070d07..992a0ae 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/BatchServiceAsync.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/BatchServiceAsync.kt @@ -12,6 +12,7 @@ import com.blooio.api.models.batches.BatchRetrieveStatusParams import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** Bulk/batch operations (stubbed) */ interface BatchServiceAsync { /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/BatchServiceAsyncImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/BatchServiceAsyncImpl.kt index 6e65f91..18c975a 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/BatchServiceAsyncImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/BatchServiceAsyncImpl.kt @@ -23,6 +23,7 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** Bulk/batch operations (stubbed) */ class BatchServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : BatchServiceAsync { diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ConfigServiceAsync.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ConfigServiceAsync.kt index 2265be1..ded859c 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ConfigServiceAsync.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ConfigServiceAsync.kt @@ -20,6 +20,7 @@ interface ConfigServiceAsync { */ fun withOptions(modifier: Consumer): ConfigServiceAsync + /** Account-level configuration */ fun webhook(): WebhookServiceAsync /** @@ -36,6 +37,7 @@ interface ConfigServiceAsync { modifier: Consumer ): ConfigServiceAsync.WithRawResponse + /** Account-level configuration */ fun webhook(): WebhookServiceAsync.WithRawResponse } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ConfigServiceAsyncImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ConfigServiceAsyncImpl.kt index 3bf4b56..aecaf95 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ConfigServiceAsyncImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ConfigServiceAsyncImpl.kt @@ -21,6 +21,7 @@ class ConfigServiceAsyncImpl internal constructor(private val clientOptions: Cli override fun withOptions(modifier: Consumer): ConfigServiceAsync = ConfigServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** Account-level configuration */ override fun webhook(): WebhookServiceAsync = webhook class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -37,6 +38,7 @@ class ConfigServiceAsyncImpl internal constructor(private val clientOptions: Cli clientOptions.toBuilder().apply(modifier::accept).build() ) + /** Account-level configuration */ override fun webhook(): WebhookServiceAsync.WithRawResponse = webhook } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ContactServiceAsync.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ContactServiceAsync.kt index 2b8defc..1588d35 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ContactServiceAsync.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ContactServiceAsync.kt @@ -10,6 +10,7 @@ import com.blooio.api.models.contacts.ContactCheckCapabilitiesResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** Contact-related operations */ interface ContactServiceAsync { /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ContactServiceAsyncImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ContactServiceAsyncImpl.kt index e00400c..b7fd70b 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ContactServiceAsyncImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ContactServiceAsyncImpl.kt @@ -21,6 +21,7 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** Contact-related operations */ class ContactServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : ContactServiceAsync { diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MeServiceAsync.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MeServiceAsync.kt index 41e1b52..ec55599 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MeServiceAsync.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MeServiceAsync.kt @@ -10,6 +10,7 @@ import com.blooio.api.models.me.MeRetrieveResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** Account and API key information */ interface MeServiceAsync { /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MeServiceAsyncImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MeServiceAsyncImpl.kt index 1e01eb7..2e07d54 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MeServiceAsyncImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MeServiceAsyncImpl.kt @@ -19,6 +19,7 @@ import com.blooio.api.models.me.MeRetrieveResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** Account and API key information */ class MeServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : MeServiceAsync { diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MessageServiceAsync.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MessageServiceAsync.kt index 114e4e4..dbbe25c 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MessageServiceAsync.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MessageServiceAsync.kt @@ -16,6 +16,7 @@ import com.blooio.api.models.messages.MessageSendResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** Send and manage individual messages */ interface MessageServiceAsync { /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MessageServiceAsyncImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MessageServiceAsyncImpl.kt index 1d3ac4f..d225a4c 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MessageServiceAsyncImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MessageServiceAsyncImpl.kt @@ -28,6 +28,7 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** Send and manage individual messages */ class MessageServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : MessageServiceAsync { diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/config/WebhookServiceAsync.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/config/WebhookServiceAsync.kt index 5836648..f5e0597 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/config/WebhookServiceAsync.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/config/WebhookServiceAsync.kt @@ -12,6 +12,7 @@ import com.blooio.api.models.config.webhook.WebhookUpdateResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** Account-level configuration */ interface WebhookServiceAsync { /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncImpl.kt index 13cf8c9..73a4fa5 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncImpl.kt @@ -22,6 +22,7 @@ import com.blooio.api.models.config.webhook.WebhookUpdateResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** Account-level configuration */ class WebhookServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : WebhookServiceAsync { diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/BatchService.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/BatchService.kt index 4b78e4c..778416c 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/BatchService.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/BatchService.kt @@ -12,6 +12,7 @@ import com.blooio.api.models.batches.BatchRetrieveStatusParams import com.google.errorprone.annotations.MustBeClosed import java.util.function.Consumer +/** Bulk/batch operations (stubbed) */ interface BatchService { /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/BatchServiceImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/BatchServiceImpl.kt index 94adc8a..45b8d5e 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/BatchServiceImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/BatchServiceImpl.kt @@ -22,6 +22,7 @@ import com.blooio.api.models.batches.BatchRetrieveStatusParams import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** Bulk/batch operations (stubbed) */ class BatchServiceImpl internal constructor(private val clientOptions: ClientOptions) : BatchService { diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ConfigService.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ConfigService.kt index c8c480c..e0a612c 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ConfigService.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ConfigService.kt @@ -20,6 +20,7 @@ interface ConfigService { */ fun withOptions(modifier: Consumer): ConfigService + /** Account-level configuration */ fun webhook(): WebhookService /** A view of [ConfigService] that provides access to raw HTTP responses for each method. */ @@ -32,6 +33,7 @@ interface ConfigService { */ fun withOptions(modifier: Consumer): ConfigService.WithRawResponse + /** Account-level configuration */ fun webhook(): WebhookService.WithRawResponse } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ConfigServiceImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ConfigServiceImpl.kt index eb323dd..23e0c52 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ConfigServiceImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ConfigServiceImpl.kt @@ -21,6 +21,7 @@ class ConfigServiceImpl internal constructor(private val clientOptions: ClientOp override fun withOptions(modifier: Consumer): ConfigService = ConfigServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** Account-level configuration */ override fun webhook(): WebhookService = webhook class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -37,6 +38,7 @@ class ConfigServiceImpl internal constructor(private val clientOptions: ClientOp clientOptions.toBuilder().apply(modifier::accept).build() ) + /** Account-level configuration */ override fun webhook(): WebhookService.WithRawResponse = webhook } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ContactService.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ContactService.kt index 4476b6b..5ccedcb 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ContactService.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ContactService.kt @@ -10,6 +10,7 @@ import com.blooio.api.models.contacts.ContactCheckCapabilitiesResponse import com.google.errorprone.annotations.MustBeClosed import java.util.function.Consumer +/** Contact-related operations */ interface ContactService { /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ContactServiceImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ContactServiceImpl.kt index 5d8a83d..8ddffc6 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ContactServiceImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ContactServiceImpl.kt @@ -20,6 +20,7 @@ import com.blooio.api.models.contacts.ContactCheckCapabilitiesResponse import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** Contact-related operations */ class ContactServiceImpl internal constructor(private val clientOptions: ClientOptions) : ContactService { diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MeService.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MeService.kt index 4271ae5..a1b2172 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MeService.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MeService.kt @@ -10,6 +10,7 @@ import com.blooio.api.models.me.MeRetrieveResponse import com.google.errorprone.annotations.MustBeClosed import java.util.function.Consumer +/** Account and API key information */ interface MeService { /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MeServiceImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MeServiceImpl.kt index caf23d7..5776732 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MeServiceImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MeServiceImpl.kt @@ -18,6 +18,7 @@ import com.blooio.api.models.me.MeRetrieveParams import com.blooio.api.models.me.MeRetrieveResponse import java.util.function.Consumer +/** Account and API key information */ class MeServiceImpl internal constructor(private val clientOptions: ClientOptions) : MeService { private val withRawResponse: MeService.WithRawResponse by lazy { diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MessageService.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MessageService.kt index cb8919f..17012f1 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MessageService.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MessageService.kt @@ -16,6 +16,7 @@ import com.blooio.api.models.messages.MessageSendResponse import com.google.errorprone.annotations.MustBeClosed import java.util.function.Consumer +/** Send and manage individual messages */ interface MessageService { /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MessageServiceImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MessageServiceImpl.kt index b3bda00..a2056a6 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MessageServiceImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MessageServiceImpl.kt @@ -27,6 +27,7 @@ import com.blooio.api.models.messages.MessageSendResponse import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** Send and manage individual messages */ class MessageServiceImpl internal constructor(private val clientOptions: ClientOptions) : MessageService { diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/config/WebhookService.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/config/WebhookService.kt index 101cf53..f5eb09d 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/config/WebhookService.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/config/WebhookService.kt @@ -12,6 +12,7 @@ import com.blooio.api.models.config.webhook.WebhookUpdateResponse import com.google.errorprone.annotations.MustBeClosed import java.util.function.Consumer +/** Account-level configuration */ interface WebhookService { /** diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/config/WebhookServiceImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/config/WebhookServiceImpl.kt index 557dea2..28c3071 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/config/WebhookServiceImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/config/WebhookServiceImpl.kt @@ -21,6 +21,7 @@ import com.blooio.api.models.config.webhook.WebhookUpdateParams import com.blooio.api.models.config.webhook.WebhookUpdateResponse import java.util.function.Consumer +/** Account-level configuration */ class WebhookServiceImpl internal constructor(private val clientOptions: ClientOptions) : WebhookService { From e112bbf06bcdf1bb105d9bf924a29f652ac28eb4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 07:04:50 +0000 Subject: [PATCH 26/63] feat(api): manual updates --- .github/workflows/ci.yml | 26 +- .github/workflows/publish-sonatype.yml | 41 - .github/workflows/release-doctor.yml | 24 - .gitignore | 1 + .release-please-manifest.json | 3 - .stats.yml | 8 +- README.md | 111 +- SECURITY.md | 4 + bin/check-release-environment | 33 - .../api/client/okhttp/BlooioOkHttpClient.kt | 4 +- .../client/okhttp/BlooioOkHttpClientAsync.kt | 4 +- .../com/blooio/api/client/BlooioClient.kt | 59 +- .../blooio/api/client/BlooioClientAsync.kt | 59 +- .../api/client/BlooioClientAsyncImpl.kt | 114 +- .../com/blooio/api/client/BlooioClientImpl.kt | 110 +- .../main/kotlin/com/blooio/api/core/Check.kt | 2 +- .../com/blooio/api/core/ClientOptions.kt | 33 +- .../blooio/api/core/handlers/EmptyHandler.kt | 12 - .../api/core/http/RetryingHttpClient.kt | 11 +- .../blooio/api/models/chats/ChatListParams.kt | 385 ++ .../api/models/chats/ChatListResponse.kt | 1274 +++++++ .../api/models/chats/ChatMarkAsReadParams.kt | 229 ++ .../ChatMarkAsReadResponse.kt} | 151 +- .../api/models/chats/ChatRetrieveParams.kt | 189 + .../api/models/chats/ChatRetrieveResponse.kt | 1086 ++++++ .../chats/ChatShareContactCardParams.kt | 236 ++ .../chats/ChatShareContactCardResponse.kt | 227 ++ .../blooio/api/models/chats/LastMessage.kt | 383 ++ .../background/BackgroundRemoveParams.kt | 230 ++ .../background/BackgroundRetrieveParams.kt} | 53 +- .../chats/background/BackgroundSetParams.kt | 460 +++ .../background/ChatBackgroundResponse.kt | 346 ++ .../api/models/chats/messages/LinkPreview.kt | 206 ++ .../messages/MessageGetStatusParams.kt | 40 +- .../messages/MessageGetStatusResponse.kt} | 435 ++- .../chats/messages/MessageListParams.kt | 585 +++ .../chats/messages/MessageListResponse.kt | 1346 +++++++ .../chats/messages/MessageReactParams.kt | 695 ++++ .../chats/messages/MessageReactResponse.kt | 398 ++ .../messages/MessageRetrieveParams.kt | 43 +- .../chats/messages/MessageRetrieveResponse.kt | 1332 +++++++ .../chats/messages/MessageSendParams.kt | 1895 ++++++++++ .../chats/messages/MessageSendResponse.kt | 566 +++ .../api/models/chats/messages/Reaction.kt | 271 ++ .../chats/polls/PollGetResultsParams.kt | 220 ++ .../chats/polls/PollGetResultsResponse.kt | 474 +++ .../api/models/chats/polls/PollSendParams.kt | 531 +++ .../models/chats/polls/PollSendResponse.kt | 444 +++ .../api/models/chats/typing/TypingResponse.kt | 265 ++ .../models/chats/typing/TypingStartParams.kt | 229 ++ .../models/chats/typing/TypingStopParams.kt | 229 ++ .../com/blooio/api/models/contacts/Contact.kt | 573 +++ .../ContactCheckCapabilitiesParams.kt | 29 +- .../ContactCheckCapabilitiesResponse.kt | 102 +- .../models/contacts/ContactCreateParams.kt | 488 +++ .../ContactDeleteParams.kt} | 56 +- .../api/models/contacts/ContactListParams.kt | 397 ++ .../models/contacts/ContactListResponse.kt | 214 ++ .../ContactRetrieveParams.kt} | 52 +- .../models/contacts/ContactUpdateParams.kt | 413 +++ .../DeleteResponse.kt} | 102 +- .../blooio/api/models/contacts/Pagination.kt | 215 ++ .../api/models/contacts/tags/TagAddParams.kt | 463 +++ .../models/contacts/tags/TagAddResponse.kt | 213 ++ .../api/models/contacts/tags/TagListParams.kt | 189 + .../models/contacts/tags/TagListResponse.kt | 348 ++ .../models/contacts/tags/TagRemoveParams.kt | 258 ++ .../FacetimeInitiateCallParams.kt} | 120 +- .../facetime/FacetimeInitiateCallResponse.kt | 223 ++ .../com/blooio/api/models/groups/Group.kt | 683 ++++ .../GroupCreateParams.kt} | 351 +- .../api/models/groups/GroupCreateResponse.kt | 678 ++++ .../api/models/groups/GroupDeleteParams.kt | 232 ++ .../api/models/groups/GroupDeleteResponse.kt | 184 + .../api/models/groups/GroupListParams.kt | 397 ++ .../api/models/groups/GroupListResponse.kt | 213 ++ .../GroupRetrieveParams.kt} | 48 +- .../api/models/groups/GroupUpdateParams.kt | 411 +++ .../api/models/groups/GroupUpdateResponse.kt | 997 ++++++ .../api/models/groups/icon/GroupIcon.kt | 549 +++ .../models/groups/icon/IconRemoveParams.kt | 234 ++ .../api/models/groups/icon/IconSetParams.kt | 452 +++ .../api/models/groups/members/GroupMember.kt | 295 ++ .../models/groups/members/MemberAddParams.kt | 444 +++ .../members/MemberAddResponse.kt} | 88 +- .../models/groups/members/MemberListParams.kt | 243 ++ .../groups/members/MemberListResponse.kt | 326 ++ .../groups/members/MemberRemoveParams.kt | 264 ++ .../groups/members/MemberRemoveResponse.kt | 184 + .../location/contacts/ContactListParams.kt | 173 + .../location/contacts/ContactListResponse.kt | 180 + .../location/contacts/ContactLocation.kt | 290 ++ .../contacts/ContactRefreshParams.kt} | 33 +- .../contacts/ContactRefreshResponse.kt | 211 ++ .../contacts/ContactRetrieveParams.kt | 189 + .../blooio/api/models/me/MeRetrieveParams.kt | 4 +- .../api/models/me/MeRetrieveResponse.kt | 631 +++- .../api/models/me/numbers/NumberListParams.kt | 173 + .../models/me/numbers/NumberListResponse.kt | 401 +++ .../contactcard/ContactCardRetrieveParams.kt | 200 ++ .../ContactCardRetrieveResponse.kt | 605 ++++ .../contactcard/ContactCardUpdateParams.kt | 814 +++++ .../contactcard/ContactCardUpdateResponse.kt | 268 ++ .../models/messages/MessageCancelResponse.kt | 311 -- .../PhoneNumberBatchCreateParams.kt | 450 +++ .../PhoneNumberBatchCreateResponse.kt | 185 + .../phonenumbers/lookup/LookupCreateParams.kt | 419 +++ .../lookup/LookupRetrieveParams.kt | 217 ++ .../lookup/PhoneNumberLookupResult.kt | 1089 ++++++ .../com/blooio/api/models/webhooks/Webhook.kt | 875 +++++ .../models/webhooks/WebhookCreateParams.kt | 700 ++++ .../models/webhooks/WebhookCreateResponse.kt | 384 ++ .../models/webhooks/WebhookDeleteParams.kt | 229 ++ .../WebhookDeleteResponse.kt} | 60 +- .../api/models/webhooks/WebhookListParams.kt | 170 + .../models/webhooks/WebhookListResponse.kt | 178 + .../WebhookRetrieveParams.kt | 33 +- .../models/webhooks/WebhookUpdateParams.kt | 685 ++++ .../api/models/webhooks/logs/LogListParams.kt | 464 +++ .../models/webhooks/logs/LogListResponse.kt | 3190 +++++++++++++++++ .../models/webhooks/logs/LogReplayParams.kt | 258 ++ .../models/webhooks/logs/LogReplayResponse.kt | 782 ++++ .../webhooks/secret/SecretRotateParams.kt | 232 ++ .../webhooks/secret/SecretRotateResponse.kt | 319 ++ .../api/services/async/BatchServiceAsync.kt | 290 -- .../services/async/BatchServiceAsyncImpl.kt | 182 - .../api/services/async/ChatServiceAsync.kt | 356 ++ .../services/async/ChatServiceAsyncImpl.kt | 279 ++ .../services/async/ConfigServiceAsyncImpl.kt | 44 - .../api/services/async/ContactServiceAsync.kt | 340 +- .../services/async/ContactServiceAsyncImpl.kt | 226 +- .../services/async/FacetimeServiceAsync.kt | 75 + .../async/FacetimeServiceAsyncImpl.kt | 87 + .../api/services/async/GroupServiceAsync.kt | 371 ++ .../services/async/GroupServiceAsyncImpl.kt | 283 ++ ...erviceAsync.kt => LocationServiceAsync.kt} | 18 +- .../async/LocationServiceAsyncImpl.kt | 44 + .../api/services/async/MeServiceAsync.kt | 15 +- .../api/services/async/MeServiceAsyncImpl.kt | 20 +- .../api/services/async/MessageServiceAsync.kt | 321 -- .../services/async/PhoneNumberServiceAsync.kt | 91 + .../async/PhoneNumberServiceAsyncImpl.kt | 110 + .../api/services/async/WebhookServiceAsync.kt | 349 ++ .../services/async/WebhookServiceAsyncImpl.kt | 282 ++ .../async/chats/BackgroundServiceAsync.kt | 260 ++ .../async/chats/BackgroundServiceAsyncImpl.kt | 176 + .../async/chats/MessageServiceAsync.kt | 380 ++ .../{ => chats}/MessageServiceAsyncImpl.kt | 123 +- .../services/async/chats/PollServiceAsync.kt | 154 + .../async/chats/PollServiceAsyncImpl.kt | 138 + .../async/chats/TypingServiceAsync.kt | 187 + .../async/chats/TypingServiceAsyncImpl.kt | 134 + .../async/config/WebhookServiceAsync.kt | 124 - .../async/contacts/TagServiceAsync.kt | 218 ++ .../async/contacts/TagServiceAsyncImpl.kt | 177 + .../services/async/groups/IconServiceAsync.kt | 171 + .../async/groups/IconServiceAsyncImpl.kt | 135 + .../async/groups/MemberServiceAsync.kt | 235 ++ .../async/groups/MemberServiceAsyncImpl.kt | 182 + .../async/location/ContactServiceAsync.kt | 214 ++ .../async/location/ContactServiceAsyncImpl.kt | 170 + .../services/async/me/NumberServiceAsync.kt | 95 + .../async/me/NumberServiceAsyncImpl.kt | 101 + .../me/numbers/ContactCardServiceAsync.kt | 209 ++ .../me/numbers/ContactCardServiceAsyncImpl.kt | 134 + .../async/phonenumbers/LookupServiceAsync.kt | 109 + .../LookupServiceAsyncImpl.kt} | 86 +- .../async/webhooks/LogServiceAsync.kt | 163 + .../async/webhooks/LogServiceAsyncImpl.kt | 140 + .../async/webhooks/SecretServiceAsync.kt | 121 + .../async/webhooks/SecretServiceAsyncImpl.kt | 92 + .../api/services/blocking/BatchService.kt | 285 -- .../api/services/blocking/BatchServiceImpl.kt | 161 - .../api/services/blocking/ChatService.kt | 355 ++ .../api/services/blocking/ChatServiceImpl.kt | 260 ++ .../services/blocking/ConfigServiceImpl.kt | 44 - .../api/services/blocking/ContactService.kt | 338 +- .../services/blocking/ContactServiceImpl.kt | 202 +- .../api/services/blocking/FacetimeService.kt | 72 + .../services/blocking/FacetimeServiceImpl.kt | 83 + .../api/services/blocking/GroupService.kt | 360 ++ .../api/services/blocking/GroupServiceImpl.kt | 261 ++ .../{ConfigService.kt => LocationService.kt} | 18 +- .../services/blocking/LocationServiceImpl.kt | 44 + .../blooio/api/services/blocking/MeService.kt | 15 +- .../api/services/blocking/MeServiceImpl.kt | 20 +- .../api/services/blocking/MessageService.kt | 312 -- .../services/blocking/PhoneNumberService.kt | 90 + .../blocking/PhoneNumberServiceImpl.kt | 106 + .../api/services/blocking/WebhookService.kt | 342 ++ .../services/blocking/WebhookServiceImpl.kt | 260 ++ .../blocking/chats/BackgroundService.kt | 253 ++ .../blocking/chats/BackgroundServiceImpl.kt | 166 + .../services/blocking/chats/MessageService.kt | 366 ++ .../{ => chats}/MessageServiceImpl.kt | 120 +- .../services/blocking/chats/PollService.kt | 153 + .../blocking/chats/PollServiceImpl.kt | 127 + .../services/blocking/chats/TypingService.kt | 179 + .../blocking/chats/TypingServiceImpl.kt | 121 + .../blocking/config/WebhookService.kt | 120 - .../services/blocking/contacts/TagService.kt | 213 ++ .../blocking/contacts/TagServiceImpl.kt | 157 + .../services/blocking/groups/IconService.kt | 167 + .../blocking/groups/IconServiceImpl.kt | 121 + .../services/blocking/groups/MemberService.kt | 228 ++ .../blocking/groups/MemberServiceImpl.kt | 169 + .../blocking/location/ContactService.kt | 208 ++ .../blocking/location/ContactServiceImpl.kt | 160 + .../api/services/blocking/me/NumberService.kt | 90 + .../services/blocking/me/NumberServiceImpl.kt | 95 + .../blocking/me/numbers/ContactCardService.kt | 206 ++ .../me/numbers/ContactCardServiceImpl.kt | 127 + .../blocking/phonenumbers/LookupService.kt | 105 + .../LookupServiceImpl.kt} | 86 +- .../services/blocking/webhooks/LogService.kt | 159 + .../blocking/webhooks/LogServiceImpl.kt | 129 + .../blocking/webhooks/SecretService.kt | 117 + .../blocking/webhooks/SecretServiceImpl.kt | 88 + .../com/blooio/api/core/ClientOptionsTest.kt | 23 + .../api/core/http/RetryingHttpClientTest.kt | 224 +- .../api/models/chats/ChatListParamsTest.kt | 52 + .../api/models/chats/ChatListResponseTest.kt | 135 + .../ChatMarkAsReadParamsTest.kt} | 10 +- .../chats/ChatMarkAsReadResponseTest.kt | 44 + .../ChatRetrieveParamsTest.kt} | 10 +- .../models/chats/ChatRetrieveResponseTest.kt | 121 + .../ChatShareContactCardParamsTest.kt} | 10 +- .../chats/ChatShareContactCardResponseTest.kt | 51 + .../api/models/chats/LastMessageTest.kt | 47 + .../background/BackgroundRemoveParamsTest.kt | 23 + .../BackgroundRetrieveParamsTest.kt | 23 + .../background/BackgroundSetParamsTest.kt | 58 + .../background/ChatBackgroundResponseTest.kt | 50 + .../models/chats/messages/LinkPreviewTest.kt | 35 + .../messages/MessageGetStatusParamsTest.kt | 25 + .../messages/MessageGetStatusResponseTest.kt | 22 +- .../chats/messages/MessageListParamsTest.kt | 69 + .../chats/messages/MessageListResponseTest.kt | 118 + .../chats/messages/MessageReactParamsTest.kt | 64 + .../messages/MessageReactResponseTest.kt | 47 + .../messages/MessageRetrieveParamsTest.kt | 25 + .../messages/MessageRetrieveResponseTest.kt | 124 + .../chats/messages/MessageSendParamsTest.kt | 153 + .../chats/messages/MessageSendResponseTest.kt | 57 + .../api/models/chats/messages/ReactionTest.kt | 47 + .../chats/polls/PollGetResultsParamsTest.kt | 24 + .../chats/polls/PollGetResultsResponseTest.kt | 52 + .../models/chats/polls/PollSendParamsTest.kt | 63 + .../chats/polls/PollSendResponseTest.kt | 48 + .../models/chats/typing/TypingResponseTest.kt | 47 + .../typing/TypingStartParamsTest.kt} | 10 +- .../chats/typing/TypingStopParamsTest.kt | 23 + .../webhook/WebhookRetrieveParamsTest.kt | 13 - .../webhook/WebhookRetrieveResponseTest.kt | 41 - .../config/webhook/WebhookUpdateParamsTest.kt | 24 - .../webhook/WebhookUpdateResponseTest.kt | 41 - .../ContactCheckCapabilitiesParamsTest.kt | 6 +- .../ContactCheckCapabilitiesResponseTest.kt | 17 +- .../contacts/ContactCreateParamsTest.kt | 34 + .../contacts/ContactDeleteParamsTest.kt | 23 + .../models/contacts/ContactListParamsTest.kt | 52 + .../contacts/ContactListResponseTest.kt | 77 + .../contacts/ContactRetrieveParamsTest.kt | 23 + .../blooio/api/models/contacts/ContactTest.kt | 57 + .../contacts/ContactUpdateParamsTest.kt | 40 + .../api/models/contacts/DeleteResponseTest.kt | 33 + .../api/models/contacts/PaginationTest.kt | 34 + .../models/contacts/tags/TagAddParamsTest.kt | 42 + .../contacts/tags/TagAddResponseTest.kt | 44 + .../models/contacts/tags/TagListParamsTest.kt | 23 + .../contacts/tags/TagListResponseTest.kt | 40 + .../contacts/tags/TagRemoveParamsTest.kt | 24 + .../FacetimeInitiateCallParamsTest.kt | 23 + .../FacetimeInitiateCallResponseTest.kt | 45 + .../models/groups/GroupCreateParamsTest.kt | 46 + .../models/groups/GroupCreateResponseTest.kt | 73 + .../GroupDeleteParamsTest.kt} | 10 +- .../models/groups/GroupDeleteResponseTest.kt | 33 + .../api/models/groups/GroupListParamsTest.kt | 52 + .../models/groups/GroupListResponseTest.kt | 84 + .../models/groups/GroupRetrieveParamsTest.kt | 23 + .../com/blooio/api/models/groups/GroupTest.kt | 62 + .../models/groups/GroupUpdateParamsTest.kt | 40 + .../models/groups/GroupUpdateResponseTest.kt | 91 + .../api/models/groups/icon/GroupIconTest.kt | 72 + .../icon/IconRemoveParamsTest.kt} | 10 +- .../models/groups/icon/IconSetParamsTest.kt | 58 + .../models/groups/members/GroupMemberTest.kt | 50 + .../groups/members/MemberAddParamsTest.kt | 34 + .../groups/members/MemberAddResponseTest.kt | 66 + .../groups/members/MemberListParamsTest.kt | 44 + .../groups/members/MemberListResponseTest.kt | 78 + .../groups/members/MemberRemoveParamsTest.kt | 28 + .../members/MemberRemoveResponseTest.kt | 35 + .../contacts/ContactListParamsTest.kt | 13 + .../contacts/ContactListResponseTest.kt | 61 + .../location/contacts/ContactLocationTest.kt | 48 + .../contacts/ContactRefreshParamsTest.kt | 13 + .../contacts/ContactRefreshResponseTest.kt | 64 + .../contacts/ContactRetrieveParamsTest.kt | 23 + .../api/models/me/MeRetrieveResponseTest.kt | 73 +- .../numbers/NumberListParamsTest.kt} | 6 +- .../me/numbers/NumberListResponseTest.kt | 59 + .../ContactCardRetrieveParamsTest.kt | 23 + .../ContactCardRetrieveResponseTest.kt | 75 + .../ContactCardUpdateParamsTest.kt | 74 + .../ContactCardUpdateResponseTest.kt | 47 + .../messages/MessageCancelResponseTest.kt | 50 - .../messages/MessageRetrieveResponseTest.kt | 69 - .../models/messages/MessageSendParamsTest.kt | 77 - .../messages/MessageSendResponseTest.kt | 35 - .../PhoneNumberBatchCreateParamsTest.kt | 28 + .../PhoneNumberBatchCreateResponseTest.kt | 111 + .../lookup/LookupCreateParamsTest.kt | 23 + .../lookup/LookupRetrieveParamsTest.kt | 25 + .../lookup/PhoneNumberLookupResultTest.kt | 97 + .../webhooks/WebhookCreateParamsTest.kt | 43 + .../webhooks/WebhookCreateResponseTest.kt | 47 + .../webhooks/WebhookDeleteParamsTest.kt | 23 + .../webhooks/WebhookDeleteResponseTest.kt | 35 + .../models/webhooks/WebhookListParamsTest.kt | 13 + .../webhooks/WebhookListResponseTest.kt | 85 + .../webhooks/WebhookRetrieveParamsTest.kt | 23 + .../blooio/api/models/webhooks/WebhookTest.kt | 68 + .../webhooks/WebhookUpdateParamsTest.kt | 52 + .../models/webhooks/logs/LogListParamsTest.kt | 69 + .../webhooks/logs/LogListResponseTest.kt | 231 ++ .../webhooks/logs/LogReplayParamsTest.kt | 25 + .../webhooks/logs/LogReplayResponseTest.kt | 91 + .../webhooks/secret/SecretRotateParamsTest.kt | 23 + .../secret/SecretRotateResponseTest.kt | 50 + .../services/async/BatchServiceAsyncTest.kt | 54 - .../services/async/ChatServiceAsyncTest.kt | 67 + .../services/async/ContactServiceAsyncTest.kt | 79 +- .../async/FacetimeServiceAsyncTest.kt | 26 + .../services/async/GroupServiceAsyncTest.kt | 95 + .../services/async/MessageServiceAsyncTest.kt | 69 - .../async/PhoneNumberServiceAsyncTest.kt | 28 + .../services/async/WebhookServiceAsyncTest.kt | 87 + .../async/chats/BackgroundServiceAsyncTest.kt | 53 + .../async/chats/MessageServiceAsyncTest.kt | 135 + .../async/chats/PollServiceAsyncTest.kt | 47 + .../async/chats/TypingServiceAsyncTest.kt | 34 + .../async/config/WebhookServiceAsyncTest.kt | 38 - .../async/contacts/TagServiceAsyncTest.kt | 58 + .../async/groups/IconServiceAsyncTest.kt | 41 + .../async/groups/MemberServiceAsyncTest.kt | 64 + .../async/location/ContactServiceAsyncTest.kt | 46 + .../async/me/NumberServiceAsyncTest.kt | 22 + .../me/numbers/ContactCardServiceAsyncTest.kt | 50 + .../phonenumbers/LookupServiceAsyncTest.kt | 40 + .../async/webhooks/LogServiceAsyncTest.kt | 50 + .../async/webhooks/SecretServiceAsyncTest.kt | 22 + .../api/services/blocking/ChatServiceTest.kt | 63 + .../services/blocking/ContactServiceTest.kt | 74 +- .../services/blocking/FacetimeServiceTest.kt | 25 + .../api/services/blocking/GroupServiceTest.kt | 90 + .../services/blocking/MessageServiceTest.kt | 65 - .../blocking/PhoneNumberServiceTest.kt | 27 + .../services/blocking/WebhookServiceTest.kt | 82 + .../blocking/chats/BackgroundServiceTest.kt | 50 + .../blocking/chats/MessageServiceTest.kt | 130 + .../blocking/chats/PollServiceTest.kt | 45 + .../blocking/chats/TypingServiceTest.kt | 32 + .../blocking/config/WebhookServiceTest.kt | 36 - .../blocking/contacts/TagServiceTest.kt | 55 + .../blocking/groups/IconServiceTest.kt | 39 + .../blocking/groups/MemberServiceTest.kt | 61 + .../ContactServiceTest.kt} | 35 +- .../services/blocking/me/NumberServiceTest.kt | 21 + .../me/numbers/ContactCardServiceTest.kt | 48 + .../phonenumbers/LookupServiceTest.kt | 36 + .../blocking/webhooks/LogServiceTest.kt | 48 + .../blocking/webhooks/SecretServiceTest.kt | 21 + blooio-java-example/build.gradle.kts | 3 +- .../api/proguard/ProGuardCompatibilityTest.kt | 33 +- build.gradle.kts | 2 +- .../src/main/kotlin/blooio.java.gradle.kts | 2 +- .../src/main/kotlin/blooio.kotlin.gradle.kts | 2 +- .../src/main/kotlin/blooio.publish.gradle.kts | 13 +- release-please-config.json | 67 - scripts/fast-format | 6 +- 382 files changed, 62841 insertions(+), 4537 deletions(-) delete mode 100644 .github/workflows/publish-sonatype.yml delete mode 100644 .github/workflows/release-doctor.yml delete mode 100644 .release-please-manifest.json delete mode 100644 bin/check-release-environment delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/core/handlers/EmptyHandler.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatListParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatListResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatMarkAsReadParams.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{messages/MessageGetStatusResponse.kt => chats/ChatMarkAsReadResponse.kt} (69%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatRetrieveParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatRetrieveResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatShareContactCardParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatShareContactCardResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/LastMessage.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/BackgroundRemoveParams.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{batches/BatchListMessagesParams.kt => chats/background/BackgroundRetrieveParams.kt} (77%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/BackgroundSetParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/ChatBackgroundResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/LinkPreview.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{ => chats}/messages/MessageGetStatusParams.kt (84%) rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{messages/MessageRetrieveResponse.kt => chats/messages/MessageGetStatusResponse.kt} (65%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageListParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageListResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageReactParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageReactResponse.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{ => chats}/messages/MessageRetrieveParams.kt (84%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageRetrieveResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageSendParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageSendResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/Reaction.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/polls/PollGetResultsParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/polls/PollGetResultsResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/polls/PollSendParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/polls/PollSendResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/typing/TypingResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/typing/TypingStartParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/typing/TypingStopParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/contacts/Contact.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/contacts/ContactCreateParams.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{messages/MessageCancelParams.kt => contacts/ContactDeleteParams.kt} (82%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/contacts/ContactListParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/contacts/ContactListResponse.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{batches/BatchRetrieveStatusParams.kt => contacts/ContactRetrieveParams.kt} (78%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/contacts/ContactUpdateParams.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{config/webhook/WebhookRetrieveResponse.kt => contacts/DeleteResponse.kt} (51%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/contacts/Pagination.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/contacts/tags/TagAddParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/contacts/tags/TagAddResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/contacts/tags/TagListParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/contacts/tags/TagListResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/contacts/tags/TagRemoveParams.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{config/webhook/WebhookUpdateParams.kt => facetime/FacetimeInitiateCallParams.kt} (75%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/facetime/FacetimeInitiateCallResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/Group.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{messages/MessageSendParams.kt => groups/GroupCreateParams.kt} (58%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/GroupCreateResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/GroupDeleteParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/GroupDeleteResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/GroupListParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/GroupListResponse.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{batches/BatchRetrieveParams.kt => groups/GroupRetrieveParams.kt} (82%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/GroupUpdateParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/GroupUpdateResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/icon/GroupIcon.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/icon/IconRemoveParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/icon/IconSetParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/members/GroupMember.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/members/MemberAddParams.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{messages/MessageSendResponse.kt => groups/members/MemberAddResponse.kt} (56%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/members/MemberListParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/members/MemberListResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/members/MemberRemoveParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/groups/members/MemberRemoveResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/location/contacts/ContactListParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/location/contacts/ContactListResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/location/contacts/ContactLocation.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{batches/BatchCreateParams.kt => location/contacts/ContactRefreshParams.kt} (86%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/location/contacts/ContactRefreshResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/location/contacts/ContactRetrieveParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/me/numbers/NumberListParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/me/numbers/NumberListResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/me/numbers/contactcard/ContactCardRetrieveParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/me/numbers/contactcard/ContactCardRetrieveResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/me/numbers/contactcard/ContactCardUpdateParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/me/numbers/contactcard/ContactCardUpdateResponse.kt delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageCancelResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/phonenumbers/PhoneNumberBatchCreateParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/phonenumbers/PhoneNumberBatchCreateResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/phonenumbers/lookup/LookupCreateParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/phonenumbers/lookup/LookupRetrieveParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/phonenumbers/lookup/PhoneNumberLookupResult.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/Webhook.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/WebhookCreateParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/WebhookCreateResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/WebhookDeleteParams.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{config/webhook/WebhookUpdateResponse.kt => webhooks/WebhookDeleteResponse.kt} (70%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/WebhookListParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/WebhookListResponse.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/models/{config/webhook => webhooks}/WebhookRetrieveParams.kt (83%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/WebhookUpdateParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/logs/LogListParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/logs/LogListResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/logs/LogReplayParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/logs/LogReplayResponse.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/secret/SecretRotateParams.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/models/webhooks/secret/SecretRotateResponse.kt delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/BatchServiceAsync.kt delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/BatchServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ChatServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ChatServiceAsyncImpl.kt delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/ConfigServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/FacetimeServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/FacetimeServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/GroupServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/GroupServiceAsyncImpl.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/services/async/{ConfigServiceAsync.kt => LocationServiceAsync.kt} (65%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/LocationServiceAsyncImpl.kt delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/MessageServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/PhoneNumberServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/PhoneNumberServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/WebhookServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/WebhookServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/chats/BackgroundServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/chats/BackgroundServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/chats/MessageServiceAsync.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/services/async/{ => chats}/MessageServiceAsyncImpl.kt (64%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/chats/PollServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/chats/PollServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/chats/TypingServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/chats/TypingServiceAsyncImpl.kt delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/config/WebhookServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/contacts/TagServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/contacts/TagServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/groups/IconServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/groups/IconServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/groups/MemberServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/groups/MemberServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/location/ContactServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/location/ContactServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/me/NumberServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/me/NumberServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/me/numbers/ContactCardServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/me/numbers/ContactCardServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/phonenumbers/LookupServiceAsync.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/services/async/{config/WebhookServiceAsyncImpl.kt => phonenumbers/LookupServiceAsyncImpl.kt} (62%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/webhooks/LogServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/webhooks/LogServiceAsyncImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/webhooks/SecretServiceAsync.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/async/webhooks/SecretServiceAsyncImpl.kt delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/BatchService.kt delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/BatchServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ChatService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ChatServiceImpl.kt delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/ConfigServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/FacetimeService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/FacetimeServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/GroupService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/GroupServiceImpl.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/{ConfigService.kt => LocationService.kt} (66%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/LocationServiceImpl.kt delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/MessageService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/PhoneNumberService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/PhoneNumberServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/WebhookService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/WebhookServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/chats/BackgroundService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/chats/BackgroundServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/chats/MessageService.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/{ => chats}/MessageServiceImpl.kt (63%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/chats/PollService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/chats/PollServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/chats/TypingService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/chats/TypingServiceImpl.kt delete mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/config/WebhookService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/contacts/TagService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/contacts/TagServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/groups/IconService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/groups/IconServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/groups/MemberService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/groups/MemberServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/location/ContactService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/location/ContactServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/me/NumberService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/me/NumberServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/me/numbers/ContactCardService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/me/numbers/ContactCardServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/phonenumbers/LookupService.kt rename blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/{config/WebhookServiceImpl.kt => phonenumbers/LookupServiceImpl.kt} (61%) create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/webhooks/LogService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/webhooks/LogServiceImpl.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/webhooks/SecretService.kt create mode 100644 blooio-java-core/src/main/kotlin/com/blooio/api/services/blocking/webhooks/SecretServiceImpl.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/ChatListParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/ChatListResponseTest.kt rename blooio-java-core/src/test/kotlin/com/blooio/api/models/{batches/BatchRetrieveParamsTest.kt => chats/ChatMarkAsReadParamsTest.kt} (52%) create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/ChatMarkAsReadResponseTest.kt rename blooio-java-core/src/test/kotlin/com/blooio/api/models/{messages/MessageCancelParamsTest.kt => chats/ChatRetrieveParamsTest.kt} (51%) create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/ChatRetrieveResponseTest.kt rename blooio-java-core/src/test/kotlin/com/blooio/api/models/{messages/MessageRetrieveParamsTest.kt => chats/ChatShareContactCardParamsTest.kt} (50%) create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/ChatShareContactCardResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/LastMessageTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/background/BackgroundRemoveParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/background/BackgroundRetrieveParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/background/BackgroundSetParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/background/ChatBackgroundResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/messages/LinkPreviewTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/messages/MessageGetStatusParamsTest.kt rename blooio-java-core/src/test/kotlin/com/blooio/api/models/{ => chats}/messages/MessageGetStatusResponseTest.kt (54%) create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/messages/MessageListParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/messages/MessageListResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/messages/MessageReactParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/messages/MessageReactResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/messages/MessageRetrieveParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/messages/MessageRetrieveResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/messages/MessageSendParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/messages/MessageSendResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/messages/ReactionTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/polls/PollGetResultsParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/polls/PollGetResultsResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/polls/PollSendParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/polls/PollSendResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/typing/TypingResponseTest.kt rename blooio-java-core/src/test/kotlin/com/blooio/api/models/{batches/BatchListMessagesParamsTest.kt => chats/typing/TypingStartParamsTest.kt} (51%) create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/chats/typing/TypingStopParamsTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/config/webhook/WebhookRetrieveParamsTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/config/webhook/WebhookRetrieveResponseTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/config/webhook/WebhookUpdateParamsTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/config/webhook/WebhookUpdateResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/ContactCreateParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/ContactDeleteParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/ContactListParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/ContactListResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/ContactRetrieveParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/ContactTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/ContactUpdateParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/DeleteResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/PaginationTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/tags/TagAddParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/tags/TagAddResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/tags/TagListParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/tags/TagListResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/contacts/tags/TagRemoveParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/facetime/FacetimeInitiateCallParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/facetime/FacetimeInitiateCallResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/GroupCreateParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/GroupCreateResponseTest.kt rename blooio-java-core/src/test/kotlin/com/blooio/api/models/{messages/MessageGetStatusParamsTest.kt => groups/GroupDeleteParamsTest.kt} (51%) create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/GroupDeleteResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/GroupListParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/GroupListResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/GroupRetrieveParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/GroupTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/GroupUpdateParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/GroupUpdateResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/icon/GroupIconTest.kt rename blooio-java-core/src/test/kotlin/com/blooio/api/models/{batches/BatchRetrieveStatusParamsTest.kt => groups/icon/IconRemoveParamsTest.kt} (51%) create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/icon/IconSetParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/members/GroupMemberTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/members/MemberAddParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/members/MemberAddResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/members/MemberListParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/members/MemberListResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/members/MemberRemoveParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/groups/members/MemberRemoveResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/location/contacts/ContactListParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/location/contacts/ContactListResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/location/contacts/ContactLocationTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/location/contacts/ContactRefreshParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/location/contacts/ContactRefreshResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/location/contacts/ContactRetrieveParamsTest.kt rename blooio-java-core/src/test/kotlin/com/blooio/api/models/{batches/BatchCreateParamsTest.kt => me/numbers/NumberListParamsTest.kt} (51%) create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/me/numbers/NumberListResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/me/numbers/contactcard/ContactCardRetrieveParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/me/numbers/contactcard/ContactCardRetrieveResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/me/numbers/contactcard/ContactCardUpdateParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/me/numbers/contactcard/ContactCardUpdateResponseTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/messages/MessageCancelResponseTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/messages/MessageRetrieveResponseTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/messages/MessageSendParamsTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/messages/MessageSendResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/phonenumbers/PhoneNumberBatchCreateParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/phonenumbers/PhoneNumberBatchCreateResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/phonenumbers/lookup/LookupCreateParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/phonenumbers/lookup/LookupRetrieveParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/phonenumbers/lookup/PhoneNumberLookupResultTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/WebhookCreateParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/WebhookCreateResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/WebhookDeleteParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/WebhookDeleteResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/WebhookListParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/WebhookListResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/WebhookRetrieveParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/WebhookTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/WebhookUpdateParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/logs/LogListParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/logs/LogListResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/logs/LogReplayParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/logs/LogReplayResponseTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/secret/SecretRotateParamsTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/models/webhooks/secret/SecretRotateResponseTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/BatchServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/ChatServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/FacetimeServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/GroupServiceAsyncTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/MessageServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/PhoneNumberServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/WebhookServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/chats/BackgroundServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/chats/MessageServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/chats/PollServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/chats/TypingServiceAsyncTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/config/WebhookServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/contacts/TagServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/groups/IconServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/groups/MemberServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/location/ContactServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/me/NumberServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/me/numbers/ContactCardServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/phonenumbers/LookupServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/webhooks/LogServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/async/webhooks/SecretServiceAsyncTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/ChatServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/FacetimeServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/GroupServiceTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/MessageServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/PhoneNumberServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/WebhookServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/chats/BackgroundServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/chats/MessageServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/chats/PollServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/chats/TypingServiceTest.kt delete mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/config/WebhookServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/contacts/TagServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/groups/IconServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/groups/MemberServiceTest.kt rename blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/{BatchServiceTest.kt => location/ContactServiceTest.kt} (50%) create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/me/NumberServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/me/numbers/ContactCardServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/phonenumbers/LookupServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/webhooks/LogServiceTest.kt create mode 100644 blooio-java-core/src/test/kotlin/com/blooio/api/services/blocking/webhooks/SecretServiceTest.kt delete mode 100644 release-please-config.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2915cd2..3081312 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,14 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' @@ -17,7 +19,7 @@ jobs: timeout-minutes: 15 name: lint runs-on: ${{ github.repository == 'stainless-sdks/blooio-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - uses: actions/checkout@v6 @@ -44,7 +46,7 @@ jobs: contents: read id-token: write runs-on: ${{ github.repository == 'stainless-sdks/blooio-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - uses: actions/checkout@v6 @@ -65,14 +67,18 @@ jobs: run: ./scripts/build - name: Get GitHub OIDC Token - if: github.repository == 'stainless-sdks/blooio-java' + if: |- + github.repository == 'stainless-sdks/blooio-java' && + !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc uses: actions/github-script@v8 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Build and upload Maven artifacts - if: github.repository == 'stainless-sdks/blooio-java' + if: |- + github.repository == 'stainless-sdks/blooio-java' && + !startsWith(github.ref, 'refs/heads/stl/') env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml deleted file mode 100644 index 2d81e3a..0000000 --- a/.github/workflows/publish-sonatype.yml +++ /dev/null @@ -1,41 +0,0 @@ -# This workflow is triggered when a GitHub release is created. -# It can also be run manually to re-publish to Sonatype in case it failed for some reason. -# You can run this workflow by navigating to https://www.github.com/Blooio/blooio-java-sdk/actions/workflows/publish-sonatype.yml -name: Publish Sonatype -on: - workflow_dispatch: - - release: - types: [published] - -jobs: - publish: - name: publish - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6 - - - name: Set up Java - uses: actions/setup-java@v5 - with: - distribution: temurin - java-version: | - 8 - 21 - cache: gradle - - - name: Set up Gradle - uses: gradle/gradle-build-action@v2 - - - name: Publish to Sonatype - run: |- - export -- GPG_SIGNING_KEY_ID - printenv -- GPG_SIGNING_KEY | gpg --batch --passphrase-fd 3 --import 3<<< "$GPG_SIGNING_PASSWORD" - GPG_SIGNING_KEY_ID="$(gpg --with-colons --list-keys | awk -F : -- '/^pub:/ { getline; print "0x" substr($10, length($10) - 7) }')" - ./gradlew publish --no-configuration-cache - env: - SONATYPE_USERNAME: ${{ secrets.BLOOIO_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} - SONATYPE_PASSWORD: ${{ secrets.BLOOIO_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} - GPG_SIGNING_KEY: ${{ secrets.BLOOIO_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} - GPG_SIGNING_PASSWORD: ${{ secrets.BLOOIO_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml deleted file mode 100644 index 2d36b26..0000000 --- a/.github/workflows/release-doctor.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Release Doctor -on: - pull_request: - branches: - - main - workflow_dispatch: - -jobs: - release_doctor: - name: release doctor - runs-on: ubuntu-latest - if: github.repository == 'Blooio/blooio-java-sdk' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') - - steps: - - uses: actions/checkout@v6 - - - name: Check release environment - run: | - bash ./bin/check-release-environment - env: - SONATYPE_USERNAME: ${{ secrets.BLOOIO_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} - SONATYPE_PASSWORD: ${{ secrets.BLOOIO_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} - GPG_SIGNING_KEY: ${{ secrets.BLOOIO_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} - GPG_SIGNING_PASSWORD: ${{ secrets.BLOOIO_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} diff --git a/.gitignore b/.gitignore index b1346e6..90b85e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .prism.log +.stdy.log .gradle .idea .kotlin diff --git a/.release-please-manifest.json b/.release-please-manifest.json deleted file mode 100644 index 2ed3b71..0000000 --- a/.release-please-manifest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - ".": "0.0.4" -} \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 5906eac..85efcf0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 12 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/blooio%2Fblooio-2d1e4d94ef5b48617299b653eb3509f32fe4e9d6315ee9f3bac50b83635d736b.yml -openapi_spec_hash: 27229154f39588fcc348a91e6b293664 -config_hash: 8cae0b4155e1a7413f8d8693d7253e37 +configured_endpoints: 54 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/blooio/blooio-da8c56bcab4e4ad076aacfdd5f7d5650de8ad6c3a4bb4be17ee3dca2e14724bc.yml +openapi_spec_hash: 11d9b0407bffe03ac9ca3a91f11b2c3d +config_hash: 6b6c2172dff7ef13c233830fab6efadb diff --git a/README.md b/README.md index 1215874..0c60ca5 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,16 @@ # Blooio Java API Library - - [![Maven Central](https://img.shields.io/maven-central/v/com.blooio.api/blooio-java)](https://central.sonatype.com/artifact/com.blooio.api/blooio-java/0.0.4) [![javadoc](https://javadoc.io/badge2/com.blooio.api/blooio-java/0.0.4/javadoc.svg)](https://javadoc.io/doc/com.blooio.api/blooio-java/0.0.4) - - -The Blooio Java SDK provides convenient access to the Blooio REST API from applications written in Java. +The Blooio Java SDK provides convenient access to the [Blooio REST API](https://blooio.com) from applications written in Java. It is generated with [Stainless](https://www.stainless.com/). - - -Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.blooio.api/blooio-java/0.0.4). - - +The REST API documentation can be found on [blooio.com](https://blooio.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.blooio.api/blooio-java/0.0.4). ## Installation - - ### Gradle ```kotlin @@ -37,8 +27,6 @@ implementation("com.blooio.api:blooio-java:0.0.4") ``` - - ## Requirements This library requires Java 8 or later. @@ -98,10 +86,10 @@ BlooioClient client = BlooioOkHttpClient.builder() See this table for the available options: -| Setter | System property | Environment variable | Required | Default value | -| --------- | ---------------- | -------------------- | -------- | ------------------------------ | -| `apiKey` | `blooio.apiKey` | `BLOOIO_API_KEY` | true | - | -| `baseUrl` | `blooio.baseUrl` | `BLOOIO_BASE_URL` | true | `"https://backend.blooio.com"` | +| Setter | System property | Environment variable | Required | Default value | +| --------- | ---------------- | -------------------- | -------- | ------------------------------------- | +| `apiKey` | `blooio.apiKey` | `BLOOIO_API_KEY` | true | - | +| `baseUrl` | `blooio.baseUrl` | `BLOOIO_BASE_URL` | true | `"https://backend.blooio.com/v2/api"` | System properties take precedence over environment variables. @@ -174,6 +162,70 @@ CompletableFuture me = client.me().retrieve(); The asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s. +## File uploads + +The SDK defines methods that accept files. + +To upload a file, pass a [`Path`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html): + +```java +import com.blooio.api.models.groups.icon.GroupIcon; +import com.blooio.api.models.groups.icon.IconSetParams; +import java.nio.file.Paths; + +IconSetParams params = IconSetParams.builder() + .groupId("grp_abc123def456") + .icon(Paths.get("/path/to/file")) + .build(); +GroupIcon groupIcon = client.groups().icon().set(params); +``` + +Or an arbitrary [`InputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html): + +```java +import com.blooio.api.models.groups.icon.GroupIcon; +import com.blooio.api.models.groups.icon.IconSetParams; +import java.net.URL; + +IconSetParams params = IconSetParams.builder() + .groupId("grp_abc123def456") + .icon(new URL("https://example.com//path/to/file").openStream()) + .build(); +GroupIcon groupIcon = client.groups().icon().set(params); +``` + +Or a `byte[]` array: + +```java +import com.blooio.api.models.groups.icon.GroupIcon; +import com.blooio.api.models.groups.icon.IconSetParams; + +IconSetParams params = IconSetParams.builder() + .groupId("grp_abc123def456") + .icon("content".getBytes()) + .build(); +GroupIcon groupIcon = client.groups().icon().set(params); +``` + +Note that when passing a non-`Path` its filename is unknown so it will not be included in the request. To manually set a filename, pass a [`MultipartField`](blooio-java-core/src/main/kotlin/com/blooio/api/core/Values.kt): + +```java +import com.blooio.api.core.MultipartField; +import com.blooio.api.models.groups.icon.GroupIcon; +import com.blooio.api.models.groups.icon.IconSetParams; +import java.io.InputStream; +import java.net.URL; + +IconSetParams params = IconSetParams.builder() + .groupId("grp_abc123def456") + .icon(MultipartField.builder() + .value(new URL("https://example.com//path/to/file").openStream()) + .filename("/path/to/file") + .build()) + .build(); +GroupIcon groupIcon = client.groups().icon().set(params); +``` + ## Raw responses The SDK defines methods that deserialize responses into instances of Java classes. However, these methods don't provide access to the response headers, status code, or the raw response body. @@ -430,6 +482,21 @@ MeRetrieveParams params = MeRetrieveParams.builder() These can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods. +To set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class: + +```java +import com.blooio.api.core.JsonValue; +import com.blooio.api.models.me.numbers.contactcard.ContactCardUpdateParams; + +ContactCardUpdateParams params = ContactCardUpdateParams.builder() + .sharing(ContactCardUpdateParams.Sharing.builder() + .putAdditionalProperty("secretProperty", JsonValue.from("42")) + .build()) + .build(); +``` + +These properties can be accessed on the nested built object later using the `_additionalProperties()` method. + To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](blooio-java-core/src/main/kotlin/com/blooio/api/core/Values.kt) object to its setter: ```java @@ -483,11 +550,11 @@ To forcibly omit a required parameter or property, pass [`JsonMissing`](blooio-j ```java import com.blooio.api.core.JsonMissing; -import com.blooio.api.models.contacts.ContactCheckCapabilitiesParams; import com.blooio.api.models.me.MeRetrieveParams; +import com.blooio.api.models.me.numbers.contactcard.ContactCardRetrieveParams; -MeRetrieveParams params = ContactCheckCapabilitiesParams.builder() - .contact(JsonMissing.of()) +MeRetrieveParams params = ContactCardRetrieveParams.builder() + .number(JsonMissing.of()) .build(); ``` @@ -617,4 +684,4 @@ This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) con We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. -We are keen for your feedback; please open an [issue](https://www.github.com/Blooio/blooio-java-sdk/issues) with questions, bugs, or suggestions. +We are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/blooio-java/issues) with questions, bugs, or suggestions. diff --git a/SECURITY.md b/SECURITY.md index ea78ff0..4262c82 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -18,6 +18,10 @@ before making any information public. If you encounter security issues that are not directly related to SDKs but pertain to the services or products provided by Blooio, please follow the respective company's security reporting guidelines. +### Blooio Terms and Policies + +Please contact support@blooio.com for any questions or concerns regarding the security of our services. + --- Thank you for helping us keep the SDKs and systems they interact with secure. diff --git a/bin/check-release-environment b/bin/check-release-environment deleted file mode 100644 index 3a6a7b4..0000000 --- a/bin/check-release-environment +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash - -errors=() - -if [ -z "${SONATYPE_USERNAME}" ]; then - errors+=("The SONATYPE_USERNAME secret has not been set. Please set it in either this repository's secrets or your organization secrets") -fi - -if [ -z "${SONATYPE_PASSWORD}" ]; then - errors+=("The SONATYPE_PASSWORD secret has not been set. Please set it in either this repository's secrets or your organization secrets") -fi - -if [ -z "${GPG_SIGNING_KEY}" ]; then - errors+=("The GPG_SIGNING_KEY secret has not been set. Please set it in either this repository's secrets or your organization secrets") -fi - -if [ -z "${GPG_SIGNING_PASSWORD}" ]; then - errors+=("The GPG_SIGNING_PASSWORD secret has not been set. Please set it in either this repository's secrets or your organization secrets") -fi - -lenErrors=${#errors[@]} - -if [[ lenErrors -gt 0 ]]; then - echo -e "Found the following errors in the release environment:\n" - - for error in "${errors[@]}"; do - echo -e "- $error\n" - done - - exit 1 -fi - -echo "The environment is ready to push releases!" diff --git a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt index c409e2c..12f120f 100644 --- a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt +++ b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClient.kt @@ -207,7 +207,7 @@ class BlooioOkHttpClient private constructor() { /** * The base URL to use for every request. * - * Defaults to the production environment: `https://backend.blooio.com`. + * Defaults to the production environment: `https://backend.blooio.com/v2/api`. */ fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } @@ -258,7 +258,7 @@ class BlooioOkHttpClient private constructor() { */ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } - /** API key must be provided in the Authorization header as `Bearer YOUR_API_KEY`. */ + /** API key authentication. Use your API key as the bearer token. */ fun apiKey(apiKey: String) = apply { clientOptions.apiKey(apiKey) } fun headers(headers: Headers) = apply { clientOptions.headers(headers) } diff --git a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt index ccc14ff..2cd6ba7 100644 --- a/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt +++ b/blooio-java-client-okhttp/src/main/kotlin/com/blooio/api/client/okhttp/BlooioOkHttpClientAsync.kt @@ -207,7 +207,7 @@ class BlooioOkHttpClientAsync private constructor() { /** * The base URL to use for every request. * - * Defaults to the production environment: `https://backend.blooio.com`. + * Defaults to the production environment: `https://backend.blooio.com/v2/api`. */ fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } @@ -258,7 +258,7 @@ class BlooioOkHttpClientAsync private constructor() { */ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } - /** API key must be provided in the Authorization header as `Bearer YOUR_API_KEY`. */ + /** API key authentication. Use your API key as the bearer token. */ fun apiKey(apiKey: String) = apply { clientOptions.apiKey(apiKey) } fun headers(headers: Headers) = apply { clientOptions.headers(headers) } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClient.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClient.kt index 934a821..97d034c 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClient.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClient.kt @@ -3,11 +3,14 @@ package com.blooio.api.client import com.blooio.api.core.ClientOptions -import com.blooio.api.services.blocking.BatchService -import com.blooio.api.services.blocking.ConfigService +import com.blooio.api.services.blocking.ChatService import com.blooio.api.services.blocking.ContactService +import com.blooio.api.services.blocking.FacetimeService +import com.blooio.api.services.blocking.GroupService +import com.blooio.api.services.blocking.LocationService import com.blooio.api.services.blocking.MeService -import com.blooio.api.services.blocking.MessageService +import com.blooio.api.services.blocking.PhoneNumberService +import com.blooio.api.services.blocking.WebhookService import java.util.function.Consumer /** @@ -46,19 +49,30 @@ interface BlooioClient { */ fun withOptions(modifier: Consumer): BlooioClient - /** Account and API key information */ + /** Authentication and account information */ fun me(): MeService - /** Contact-related operations */ + /** Manage contacts (phone numbers and emails) */ fun contacts(): ContactService - /** Send and manage individual messages */ - fun messages(): MessageService + fun location(): LocationService - fun config(): ConfigService + /** Initiate FaceTime calls */ + fun facetime(): FacetimeService - /** Bulk/batch operations (stubbed) */ - fun batches(): BatchService + /** Manage contact groups */ + fun groups(): GroupService + + /** Manage webhook subscriptions */ + fun webhooks(): WebhookService + + fun chats(): ChatService + + /** + * Phone number validation, formatting, and NANPA geocoding. Requires an Enterprise plan + * (Dedicated Enterprise). + */ + fun phoneNumbers(): PhoneNumberService /** * Closes this client, relinquishing any underlying resources. @@ -83,18 +97,29 @@ interface BlooioClient { */ fun withOptions(modifier: Consumer): BlooioClient.WithRawResponse - /** Account and API key information */ + /** Authentication and account information */ fun me(): MeService.WithRawResponse - /** Contact-related operations */ + /** Manage contacts (phone numbers and emails) */ fun contacts(): ContactService.WithRawResponse - /** Send and manage individual messages */ - fun messages(): MessageService.WithRawResponse + fun location(): LocationService.WithRawResponse - fun config(): ConfigService.WithRawResponse + /** Initiate FaceTime calls */ + fun facetime(): FacetimeService.WithRawResponse - /** Bulk/batch operations (stubbed) */ - fun batches(): BatchService.WithRawResponse + /** Manage contact groups */ + fun groups(): GroupService.WithRawResponse + + /** Manage webhook subscriptions */ + fun webhooks(): WebhookService.WithRawResponse + + fun chats(): ChatService.WithRawResponse + + /** + * Phone number validation, formatting, and NANPA geocoding. Requires an Enterprise plan + * (Dedicated Enterprise). + */ + fun phoneNumbers(): PhoneNumberService.WithRawResponse } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsync.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsync.kt index c205669..0a3eafc 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsync.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsync.kt @@ -3,11 +3,14 @@ package com.blooio.api.client import com.blooio.api.core.ClientOptions -import com.blooio.api.services.async.BatchServiceAsync -import com.blooio.api.services.async.ConfigServiceAsync +import com.blooio.api.services.async.ChatServiceAsync import com.blooio.api.services.async.ContactServiceAsync +import com.blooio.api.services.async.FacetimeServiceAsync +import com.blooio.api.services.async.GroupServiceAsync +import com.blooio.api.services.async.LocationServiceAsync import com.blooio.api.services.async.MeServiceAsync -import com.blooio.api.services.async.MessageServiceAsync +import com.blooio.api.services.async.PhoneNumberServiceAsync +import com.blooio.api.services.async.WebhookServiceAsync import java.util.function.Consumer /** @@ -46,19 +49,30 @@ interface BlooioClientAsync { */ fun withOptions(modifier: Consumer): BlooioClientAsync - /** Account and API key information */ + /** Authentication and account information */ fun me(): MeServiceAsync - /** Contact-related operations */ + /** Manage contacts (phone numbers and emails) */ fun contacts(): ContactServiceAsync - /** Send and manage individual messages */ - fun messages(): MessageServiceAsync + fun location(): LocationServiceAsync - fun config(): ConfigServiceAsync + /** Initiate FaceTime calls */ + fun facetime(): FacetimeServiceAsync - /** Bulk/batch operations (stubbed) */ - fun batches(): BatchServiceAsync + /** Manage contact groups */ + fun groups(): GroupServiceAsync + + /** Manage webhook subscriptions */ + fun webhooks(): WebhookServiceAsync + + fun chats(): ChatServiceAsync + + /** + * Phone number validation, formatting, and NANPA geocoding. Requires an Enterprise plan + * (Dedicated Enterprise). + */ + fun phoneNumbers(): PhoneNumberServiceAsync /** * Closes this client, relinquishing any underlying resources. @@ -85,18 +99,29 @@ interface BlooioClientAsync { modifier: Consumer ): BlooioClientAsync.WithRawResponse - /** Account and API key information */ + /** Authentication and account information */ fun me(): MeServiceAsync.WithRawResponse - /** Contact-related operations */ + /** Manage contacts (phone numbers and emails) */ fun contacts(): ContactServiceAsync.WithRawResponse - /** Send and manage individual messages */ - fun messages(): MessageServiceAsync.WithRawResponse + fun location(): LocationServiceAsync.WithRawResponse - fun config(): ConfigServiceAsync.WithRawResponse + /** Initiate FaceTime calls */ + fun facetime(): FacetimeServiceAsync.WithRawResponse - /** Bulk/batch operations (stubbed) */ - fun batches(): BatchServiceAsync.WithRawResponse + /** Manage contact groups */ + fun groups(): GroupServiceAsync.WithRawResponse + + /** Manage webhook subscriptions */ + fun webhooks(): WebhookServiceAsync.WithRawResponse + + fun chats(): ChatServiceAsync.WithRawResponse + + /** + * Phone number validation, formatting, and NANPA geocoding. Requires an Enterprise plan + * (Dedicated Enterprise). + */ + fun phoneNumbers(): PhoneNumberServiceAsync.WithRawResponse } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsyncImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsyncImpl.kt index fc2615a..fae4817 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsyncImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientAsyncImpl.kt @@ -4,16 +4,22 @@ package com.blooio.api.client import com.blooio.api.core.ClientOptions import com.blooio.api.core.getPackageVersion -import com.blooio.api.services.async.BatchServiceAsync -import com.blooio.api.services.async.BatchServiceAsyncImpl -import com.blooio.api.services.async.ConfigServiceAsync -import com.blooio.api.services.async.ConfigServiceAsyncImpl +import com.blooio.api.services.async.ChatServiceAsync +import com.blooio.api.services.async.ChatServiceAsyncImpl import com.blooio.api.services.async.ContactServiceAsync import com.blooio.api.services.async.ContactServiceAsyncImpl +import com.blooio.api.services.async.FacetimeServiceAsync +import com.blooio.api.services.async.FacetimeServiceAsyncImpl +import com.blooio.api.services.async.GroupServiceAsync +import com.blooio.api.services.async.GroupServiceAsyncImpl +import com.blooio.api.services.async.LocationServiceAsync +import com.blooio.api.services.async.LocationServiceAsyncImpl import com.blooio.api.services.async.MeServiceAsync import com.blooio.api.services.async.MeServiceAsyncImpl -import com.blooio.api.services.async.MessageServiceAsync -import com.blooio.api.services.async.MessageServiceAsyncImpl +import com.blooio.api.services.async.PhoneNumberServiceAsync +import com.blooio.api.services.async.PhoneNumberServiceAsyncImpl +import com.blooio.api.services.async.WebhookServiceAsync +import com.blooio.api.services.async.WebhookServiceAsyncImpl import java.util.function.Consumer class BlooioClientAsyncImpl(private val clientOptions: ClientOptions) : BlooioClientAsync { @@ -39,16 +45,26 @@ class BlooioClientAsyncImpl(private val clientOptions: ClientOptions) : BlooioCl ContactServiceAsyncImpl(clientOptionsWithUserAgent) } - private val messages: MessageServiceAsync by lazy { - MessageServiceAsyncImpl(clientOptionsWithUserAgent) + private val location: LocationServiceAsync by lazy { + LocationServiceAsyncImpl(clientOptionsWithUserAgent) } - private val config: ConfigServiceAsync by lazy { - ConfigServiceAsyncImpl(clientOptionsWithUserAgent) + private val facetime: FacetimeServiceAsync by lazy { + FacetimeServiceAsyncImpl(clientOptionsWithUserAgent) } - private val batches: BatchServiceAsync by lazy { - BatchServiceAsyncImpl(clientOptionsWithUserAgent) + private val groups: GroupServiceAsync by lazy { + GroupServiceAsyncImpl(clientOptionsWithUserAgent) + } + + private val webhooks: WebhookServiceAsync by lazy { + WebhookServiceAsyncImpl(clientOptionsWithUserAgent) + } + + private val chats: ChatServiceAsync by lazy { ChatServiceAsyncImpl(clientOptionsWithUserAgent) } + + private val phoneNumbers: PhoneNumberServiceAsync by lazy { + PhoneNumberServiceAsyncImpl(clientOptionsWithUserAgent) } override fun sync(): BlooioClient = sync @@ -58,19 +74,30 @@ class BlooioClientAsyncImpl(private val clientOptions: ClientOptions) : BlooioCl override fun withOptions(modifier: Consumer): BlooioClientAsync = BlooioClientAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) - /** Account and API key information */ + /** Authentication and account information */ override fun me(): MeServiceAsync = me - /** Contact-related operations */ + /** Manage contacts (phone numbers and emails) */ override fun contacts(): ContactServiceAsync = contacts - /** Send and manage individual messages */ - override fun messages(): MessageServiceAsync = messages + override fun location(): LocationServiceAsync = location - override fun config(): ConfigServiceAsync = config + /** Initiate FaceTime calls */ + override fun facetime(): FacetimeServiceAsync = facetime - /** Bulk/batch operations (stubbed) */ - override fun batches(): BatchServiceAsync = batches + /** Manage contact groups */ + override fun groups(): GroupServiceAsync = groups + + /** Manage webhook subscriptions */ + override fun webhooks(): WebhookServiceAsync = webhooks + + override fun chats(): ChatServiceAsync = chats + + /** + * Phone number validation, formatting, and NANPA geocoding. Requires an Enterprise plan + * (Dedicated Enterprise). + */ + override fun phoneNumbers(): PhoneNumberServiceAsync = phoneNumbers override fun close() = clientOptions.close() @@ -85,16 +112,28 @@ class BlooioClientAsyncImpl(private val clientOptions: ClientOptions) : BlooioCl ContactServiceAsyncImpl.WithRawResponseImpl(clientOptions) } - private val messages: MessageServiceAsync.WithRawResponse by lazy { - MessageServiceAsyncImpl.WithRawResponseImpl(clientOptions) + private val location: LocationServiceAsync.WithRawResponse by lazy { + LocationServiceAsyncImpl.WithRawResponseImpl(clientOptions) } - private val config: ConfigServiceAsync.WithRawResponse by lazy { - ConfigServiceAsyncImpl.WithRawResponseImpl(clientOptions) + private val facetime: FacetimeServiceAsync.WithRawResponse by lazy { + FacetimeServiceAsyncImpl.WithRawResponseImpl(clientOptions) } - private val batches: BatchServiceAsync.WithRawResponse by lazy { - BatchServiceAsyncImpl.WithRawResponseImpl(clientOptions) + private val groups: GroupServiceAsync.WithRawResponse by lazy { + GroupServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val webhooks: WebhookServiceAsync.WithRawResponse by lazy { + WebhookServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val chats: ChatServiceAsync.WithRawResponse by lazy { + ChatServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val phoneNumbers: PhoneNumberServiceAsync.WithRawResponse by lazy { + PhoneNumberServiceAsyncImpl.WithRawResponseImpl(clientOptions) } override fun withOptions( @@ -104,18 +143,29 @@ class BlooioClientAsyncImpl(private val clientOptions: ClientOptions) : BlooioCl clientOptions.toBuilder().apply(modifier::accept).build() ) - /** Account and API key information */ + /** Authentication and account information */ override fun me(): MeServiceAsync.WithRawResponse = me - /** Contact-related operations */ + /** Manage contacts (phone numbers and emails) */ override fun contacts(): ContactServiceAsync.WithRawResponse = contacts - /** Send and manage individual messages */ - override fun messages(): MessageServiceAsync.WithRawResponse = messages + override fun location(): LocationServiceAsync.WithRawResponse = location + + /** Initiate FaceTime calls */ + override fun facetime(): FacetimeServiceAsync.WithRawResponse = facetime + + /** Manage contact groups */ + override fun groups(): GroupServiceAsync.WithRawResponse = groups + + /** Manage webhook subscriptions */ + override fun webhooks(): WebhookServiceAsync.WithRawResponse = webhooks - override fun config(): ConfigServiceAsync.WithRawResponse = config + override fun chats(): ChatServiceAsync.WithRawResponse = chats - /** Bulk/batch operations (stubbed) */ - override fun batches(): BatchServiceAsync.WithRawResponse = batches + /** + * Phone number validation, formatting, and NANPA geocoding. Requires an Enterprise plan + * (Dedicated Enterprise). + */ + override fun phoneNumbers(): PhoneNumberServiceAsync.WithRawResponse = phoneNumbers } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientImpl.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientImpl.kt index ff6d1b3..f8e0b0a 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientImpl.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/client/BlooioClientImpl.kt @@ -4,16 +4,22 @@ package com.blooio.api.client import com.blooio.api.core.ClientOptions import com.blooio.api.core.getPackageVersion -import com.blooio.api.services.blocking.BatchService -import com.blooio.api.services.blocking.BatchServiceImpl -import com.blooio.api.services.blocking.ConfigService -import com.blooio.api.services.blocking.ConfigServiceImpl +import com.blooio.api.services.blocking.ChatService +import com.blooio.api.services.blocking.ChatServiceImpl import com.blooio.api.services.blocking.ContactService import com.blooio.api.services.blocking.ContactServiceImpl +import com.blooio.api.services.blocking.FacetimeService +import com.blooio.api.services.blocking.FacetimeServiceImpl +import com.blooio.api.services.blocking.GroupService +import com.blooio.api.services.blocking.GroupServiceImpl +import com.blooio.api.services.blocking.LocationService +import com.blooio.api.services.blocking.LocationServiceImpl import com.blooio.api.services.blocking.MeService import com.blooio.api.services.blocking.MeServiceImpl -import com.blooio.api.services.blocking.MessageService -import com.blooio.api.services.blocking.MessageServiceImpl +import com.blooio.api.services.blocking.PhoneNumberService +import com.blooio.api.services.blocking.PhoneNumberServiceImpl +import com.blooio.api.services.blocking.WebhookService +import com.blooio.api.services.blocking.WebhookServiceImpl import java.util.function.Consumer class BlooioClientImpl(private val clientOptions: ClientOptions) : BlooioClient { @@ -37,11 +43,23 @@ class BlooioClientImpl(private val clientOptions: ClientOptions) : BlooioClient private val contacts: ContactService by lazy { ContactServiceImpl(clientOptionsWithUserAgent) } - private val messages: MessageService by lazy { MessageServiceImpl(clientOptionsWithUserAgent) } + private val location: LocationService by lazy { + LocationServiceImpl(clientOptionsWithUserAgent) + } + + private val facetime: FacetimeService by lazy { + FacetimeServiceImpl(clientOptionsWithUserAgent) + } - private val config: ConfigService by lazy { ConfigServiceImpl(clientOptionsWithUserAgent) } + private val groups: GroupService by lazy { GroupServiceImpl(clientOptionsWithUserAgent) } - private val batches: BatchService by lazy { BatchServiceImpl(clientOptionsWithUserAgent) } + private val webhooks: WebhookService by lazy { WebhookServiceImpl(clientOptionsWithUserAgent) } + + private val chats: ChatService by lazy { ChatServiceImpl(clientOptionsWithUserAgent) } + + private val phoneNumbers: PhoneNumberService by lazy { + PhoneNumberServiceImpl(clientOptionsWithUserAgent) + } override fun async(): BlooioClientAsync = async @@ -50,19 +68,30 @@ class BlooioClientImpl(private val clientOptions: ClientOptions) : BlooioClient override fun withOptions(modifier: Consumer): BlooioClient = BlooioClientImpl(clientOptions.toBuilder().apply(modifier::accept).build()) - /** Account and API key information */ + /** Authentication and account information */ override fun me(): MeService = me - /** Contact-related operations */ + /** Manage contacts (phone numbers and emails) */ override fun contacts(): ContactService = contacts - /** Send and manage individual messages */ - override fun messages(): MessageService = messages + override fun location(): LocationService = location + + /** Initiate FaceTime calls */ + override fun facetime(): FacetimeService = facetime + + /** Manage contact groups */ + override fun groups(): GroupService = groups + + /** Manage webhook subscriptions */ + override fun webhooks(): WebhookService = webhooks - override fun config(): ConfigService = config + override fun chats(): ChatService = chats - /** Bulk/batch operations (stubbed) */ - override fun batches(): BatchService = batches + /** + * Phone number validation, formatting, and NANPA geocoding. Requires an Enterprise plan + * (Dedicated Enterprise). + */ + override fun phoneNumbers(): PhoneNumberService = phoneNumbers override fun close() = clientOptions.close() @@ -77,16 +106,28 @@ class BlooioClientImpl(private val clientOptions: ClientOptions) : BlooioClient ContactServiceImpl.WithRawResponseImpl(clientOptions) } - private val messages: MessageService.WithRawResponse by lazy { - MessageServiceImpl.WithRawResponseImpl(clientOptions) + private val location: LocationService.WithRawResponse by lazy { + LocationServiceImpl.WithRawResponseImpl(clientOptions) } - private val config: ConfigService.WithRawResponse by lazy { - ConfigServiceImpl.WithRawResponseImpl(clientOptions) + private val facetime: FacetimeService.WithRawResponse by lazy { + FacetimeServiceImpl.WithRawResponseImpl(clientOptions) } - private val batches: BatchService.WithRawResponse by lazy { - BatchServiceImpl.WithRawResponseImpl(clientOptions) + private val groups: GroupService.WithRawResponse by lazy { + GroupServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val webhooks: WebhookService.WithRawResponse by lazy { + WebhookServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val chats: ChatService.WithRawResponse by lazy { + ChatServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val phoneNumbers: PhoneNumberService.WithRawResponse by lazy { + PhoneNumberServiceImpl.WithRawResponseImpl(clientOptions) } override fun withOptions( @@ -96,18 +137,29 @@ class BlooioClientImpl(private val clientOptions: ClientOptions) : BlooioClient clientOptions.toBuilder().apply(modifier::accept).build() ) - /** Account and API key information */ + /** Authentication and account information */ override fun me(): MeService.WithRawResponse = me - /** Contact-related operations */ + /** Manage contacts (phone numbers and emails) */ override fun contacts(): ContactService.WithRawResponse = contacts - /** Send and manage individual messages */ - override fun messages(): MessageService.WithRawResponse = messages + override fun location(): LocationService.WithRawResponse = location + + /** Initiate FaceTime calls */ + override fun facetime(): FacetimeService.WithRawResponse = facetime + + /** Manage contact groups */ + override fun groups(): GroupService.WithRawResponse = groups + + /** Manage webhook subscriptions */ + override fun webhooks(): WebhookService.WithRawResponse = webhooks - override fun config(): ConfigService.WithRawResponse = config + override fun chats(): ChatService.WithRawResponse = chats - /** Bulk/batch operations (stubbed) */ - override fun batches(): BatchService.WithRawResponse = batches + /** + * Phone number validation, formatting, and NANPA geocoding. Requires an Enterprise plan + * (Dedicated Enterprise). + */ + override fun phoneNumbers(): PhoneNumberService.WithRawResponse = phoneNumbers } } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/Check.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/Check.kt index 83da259..77df705 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/Check.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/Check.kt @@ -77,7 +77,7 @@ This can happen if you are either: Double-check that you are depending on compatible Jackson versions. -See https://www.github.com/Blooio/blooio-java-sdk#jackson for more information. +See https://www.github.com/stainless-sdks/blooio-java#jackson for more information. """ .trimIndent() } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/ClientOptions.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/ClientOptions.kt index 5d2f3a9..a256292 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/ClientOptions.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/ClientOptions.kt @@ -93,7 +93,7 @@ private constructor( * Defaults to 2. */ @get:JvmName("maxRetries") val maxRetries: Int, - /** API key must be provided in the Authorization header as `Bearer YOUR_API_KEY`. */ + /** API key authentication. Use your API key as the bearer token. */ @get:JvmName("apiKey") val apiKey: String, ) { @@ -106,7 +106,7 @@ private constructor( /** * The base URL to use for every request. * - * Defaults to the production environment: `https://backend.blooio.com`. + * Defaults to the production environment: `https://backend.blooio.com/v2/api`. */ fun baseUrl(): String = baseUrl ?: PRODUCTION_URL @@ -114,7 +114,7 @@ private constructor( companion object { - const val PRODUCTION_URL = "https://backend.blooio.com" + const val PRODUCTION_URL = "https://backend.blooio.com/v2/api" /** * Returns a mutable builder for constructing an instance of [ClientOptions]. @@ -220,7 +220,7 @@ private constructor( /** * The base URL to use for every request. * - * Defaults to the production environment: `https://backend.blooio.com`. + * Defaults to the production environment: `https://backend.blooio.com/v2/api`. */ fun baseUrl(baseUrl: String?) = apply { this.baseUrl = baseUrl } @@ -271,7 +271,7 @@ private constructor( */ fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries } - /** API key must be provided in the Authorization header as `Bearer YOUR_API_KEY`. */ + /** API key authentication. Use your API key as the bearer token. */ fun apiKey(apiKey: String) = apply { this.apiKey = apiKey } fun headers(headers: Headers) = apply { @@ -361,10 +361,10 @@ private constructor( * * See this table for the available options: * - * |Setter |System property |Environment variable|Required|Default value | - * |---------|----------------|--------------------|--------|------------------------------| - * |`apiKey` |`blooio.apiKey` |`BLOOIO_API_KEY` |true |- | - * |`baseUrl`|`blooio.baseUrl`|`BLOOIO_BASE_URL` |true |`"https://backend.blooio.com"`| + * |Setter |System property |Environment variable|Required|Default value | + * |---------|----------------|--------------------|--------|-------------------------------------| + * |`apiKey` |`blooio.apiKey` |`BLOOIO_API_KEY` |true |- | + * |`baseUrl`|`blooio.baseUrl`|`BLOOIO_BASE_URL` |true |`"https://backend.blooio.com/v2/api"`| * * System properties take precedence over environment variables. */ @@ -375,6 +375,14 @@ private constructor( (System.getProperty("blooio.apiKey") ?: System.getenv("BLOOIO_API_KEY"))?.let { apiKey(it) } + System.getenv("BLOOIO_CUSTOM_HEADERS")?.let { customHeadersEnv -> + for (line in customHeadersEnv.split("\n")) { + val colon = line.indexOf(':') + if (colon >= 0) { + putHeader(line.substring(0, colon).trim(), line.substring(colon + 1).trim()) + } + } + } } /** @@ -405,13 +413,14 @@ private constructor( headers.put("X-Stainless-Runtime", "JRE") headers.put("X-Stainless-Runtime-Version", getJavaVersion()) headers.put("X-Stainless-Kotlin-Version", KotlinVersion.CURRENT.toString()) + // We replace after all the default headers to allow end-users to overwrite them. + headers.replaceAll(this.headers.build()) + queryParams.replaceAll(this.queryParams.build()) apiKey.let { if (!it.isEmpty()) { - headers.put("Authorization", "Bearer $it") + headers.replace("Authorization", "Bearer $it") } } - headers.replaceAll(this.headers.build()) - queryParams.replaceAll(this.queryParams.build()) return ClientOptions( httpClient, diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/handlers/EmptyHandler.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/handlers/EmptyHandler.kt deleted file mode 100644 index 1b2fcda..0000000 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/handlers/EmptyHandler.kt +++ /dev/null @@ -1,12 +0,0 @@ -@file:JvmName("EmptyHandler") - -package com.blooio.api.core.handlers - -import com.blooio.api.core.http.HttpResponse -import com.blooio.api.core.http.HttpResponse.Handler - -@JvmSynthetic internal fun emptyHandler(): Handler = EmptyHandlerInternal - -private object EmptyHandlerInternal : Handler { - override fun handle(response: HttpResponse): Void? = null -} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt index ed77d2a..97644f6 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/core/http/RetryingHttpClient.kt @@ -201,7 +201,7 @@ private constructor( ?: headers.values("Retry-After").getOrNull(0)?.let { retryAfter -> retryAfter.toFloatOrNull()?.times(TimeUnit.SECONDS.toNanos(1)) ?: try { - ChronoUnit.MILLIS.between( + ChronoUnit.NANOS.between( OffsetDateTime.now(clock), OffsetDateTime.parse( retryAfter, @@ -214,13 +214,8 @@ private constructor( } } ?.let { retryAfterNanos -> - // If the API asks us to wait a certain amount of time (and it's a reasonable - // amount), just - // do what it says. - val retryAfter = Duration.ofNanos(retryAfterNanos.toLong()) - if (retryAfter in Duration.ofNanos(0)..Duration.ofMinutes(1)) { - return retryAfter - } + // If the API asks us to wait a certain amount of time, do what it says. + return Duration.ofNanos(retryAfterNanos.toLong()) } // Apply exponential backoff, but not more than the max. diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatListParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatListParams.kt new file mode 100644 index 0000000..0c2c079 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatListParams.kt @@ -0,0 +1,385 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats + +import com.blooio.api.core.Enum +import com.blooio.api.core.JsonField +import com.blooio.api.core.Params +import com.blooio.api.core.http.Headers +import com.blooio.api.core.http.QueryParams +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonCreator +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** List all unique conversations for the organization, sorted by most recent message. */ +class ChatListParams +private constructor( + private val limit: Long?, + private val offset: Long?, + private val q: String?, + private val sort: Sort?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Maximum number of items to return (1-200) */ + fun limit(): Optional = Optional.ofNullable(limit) + + /** Number of items to skip */ + fun offset(): Optional = Optional.ofNullable(offset) + + /** Search query (matches phone/email or contact name) */ + fun q(): Optional = Optional.ofNullable(q) + + /** Sort order */ + fun sort(): Optional = Optional.ofNullable(sort) + + /** 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(): ChatListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ChatListParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ChatListParams]. */ + class Builder internal constructor() { + + private var limit: Long? = null + private var offset: Long? = null + private var q: String? = null + private var sort: Sort? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(chatListParams: ChatListParams) = apply { + limit = chatListParams.limit + offset = chatListParams.offset + q = chatListParams.q + sort = chatListParams.sort + additionalHeaders = chatListParams.additionalHeaders.toBuilder() + additionalQueryParams = chatListParams.additionalQueryParams.toBuilder() + } + + /** Maximum number of items to return (1-200) */ + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) + + /** Alias for calling [Builder.limit] with `limit.orElse(null)`. */ + fun limit(limit: Optional) = limit(limit.getOrNull()) + + /** Number of items to skip */ + fun offset(offset: Long?) = apply { this.offset = offset } + + /** + * Alias for [Builder.offset]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun offset(offset: Long) = offset(offset as Long?) + + /** Alias for calling [Builder.offset] with `offset.orElse(null)`. */ + fun offset(offset: Optional) = offset(offset.getOrNull()) + + /** Search query (matches phone/email or contact name) */ + fun q(q: String?) = apply { this.q = q } + + /** Alias for calling [Builder.q] with `q.orElse(null)`. */ + fun q(q: Optional) = q(q.getOrNull()) + + /** Sort order */ + fun sort(sort: Sort?) = apply { this.sort = sort } + + /** Alias for calling [Builder.sort] with `sort.orElse(null)`. */ + fun sort(sort: Optional) = sort(sort.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) + } + + /** + * Returns an immutable instance of [ChatListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ChatListParams = + ChatListParams( + limit, + offset, + q, + sort, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + limit?.let { put("limit", it.toString()) } + offset?.let { put("offset", it.toString()) } + q?.let { put("q", it) } + sort?.let { put("sort", it.toString()) } + putAll(additionalQueryParams) + } + .build() + + /** Sort order */ + class Sort @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val RECENT = of("recent") + + @JvmField val OLDEST = of("oldest") + + @JvmStatic fun of(value: String) = Sort(JsonField.of(value)) + } + + /** An enum containing [Sort]'s known values. */ + enum class Known { + RECENT, + OLDEST, + } + + /** + * An enum containing [Sort]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Sort] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + RECENT, + OLDEST, + /** An enum member indicating that [Sort] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + RECENT -> Value.RECENT + OLDEST -> Value.OLDEST + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + RECENT -> Known.RECENT + OLDEST -> Known.OLDEST + else -> throw BlooioInvalidDataException("Unknown Sort: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Sort = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Sort && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ChatListParams && + limit == other.limit && + offset == other.offset && + q == other.q && + sort == other.sort && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(limit, offset, q, sort, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ChatListParams{limit=$limit, offset=$offset, q=$q, sort=$sort, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatListResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatListResponse.kt new file mode 100644 index 0000000..ab5e950 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatListResponse.kt @@ -0,0 +1,1274 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats + +import com.blooio.api.core.Enum +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.core.checkKnown +import com.blooio.api.core.toImmutable +import com.blooio.api.errors.BlooioInvalidDataException +import com.blooio.api.models.contacts.Pagination +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class ChatListResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val chats: JsonField>, + private val pagination: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("chats") @ExcludeMissing chats: JsonField> = JsonMissing.of(), + @JsonProperty("pagination") + @ExcludeMissing + pagination: JsonField = JsonMissing.of(), + ) : this(chats, pagination, mutableMapOf()) + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun chats(): Optional> = chats.getOptional("chats") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun pagination(): Optional = pagination.getOptional("pagination") + + /** + * Returns the raw JSON value of [chats]. + * + * Unlike [chats], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("chats") @ExcludeMissing fun _chats(): JsonField> = chats + + /** + * Returns the raw JSON value of [pagination]. + * + * Unlike [pagination], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pagination") + @ExcludeMissing + fun _pagination(): JsonField = pagination + + @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 [ChatListResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ChatListResponse]. */ + class Builder internal constructor() { + + private var chats: JsonField>? = null + private var pagination: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(chatListResponse: ChatListResponse) = apply { + chats = chatListResponse.chats.map { it.toMutableList() } + pagination = chatListResponse.pagination + additionalProperties = chatListResponse.additionalProperties.toMutableMap() + } + + fun chats(chats: List) = chats(JsonField.of(chats)) + + /** + * Sets [Builder.chats] to an arbitrary JSON value. + * + * You should usually call [Builder.chats] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun chats(chats: JsonField>) = apply { + this.chats = chats.map { it.toMutableList() } + } + + /** + * Adds a single [Chat] to [chats]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addChat(chat: Chat) = apply { + chats = + (chats ?: JsonField.of(mutableListOf())).also { checkKnown("chats", it).add(chat) } + } + + fun pagination(pagination: Pagination) = pagination(JsonField.of(pagination)) + + /** + * Sets [Builder.pagination] to an arbitrary JSON value. + * + * You should usually call [Builder.pagination] with a well-typed [Pagination] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun pagination(pagination: JsonField) = apply { this.pagination = pagination } + + 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 [ChatListResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ChatListResponse = + ChatListResponse( + (chats ?: JsonMissing.of()).map { it.toImmutable() }, + pagination, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ChatListResponse = apply { + if (validated) { + return@apply + } + + chats().ifPresent { it.forEach { it.validate() } } + pagination().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 = + (chats.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (pagination.asKnown().getOrNull()?.validity() ?: 0) + + class Chat + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val contact: JsonField, + private val groupId: JsonField, + private val groupName: JsonField, + private val inboundCount: JsonField, + private val isGroup: JsonField, + private val lastInboundTime: JsonField, + private val lastMessage: JsonField, + private val lastMessageTime: JsonField, + private val lastOutboundTime: JsonField, + private val memberCount: JsonField, + private val messageCount: JsonField, + private val outboundCount: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("contact") @ExcludeMissing contact: JsonField = JsonMissing.of(), + @JsonProperty("group_id") @ExcludeMissing groupId: JsonField = JsonMissing.of(), + @JsonProperty("group_name") + @ExcludeMissing + groupName: JsonField = JsonMissing.of(), + @JsonProperty("inbound_count") + @ExcludeMissing + inboundCount: JsonField = JsonMissing.of(), + @JsonProperty("is_group") + @ExcludeMissing + isGroup: JsonField = JsonMissing.of(), + @JsonProperty("last_inbound_time") + @ExcludeMissing + lastInboundTime: JsonField = JsonMissing.of(), + @JsonProperty("last_message") + @ExcludeMissing + lastMessage: JsonField = JsonMissing.of(), + @JsonProperty("last_message_time") + @ExcludeMissing + lastMessageTime: JsonField = JsonMissing.of(), + @JsonProperty("last_outbound_time") + @ExcludeMissing + lastOutboundTime: JsonField = JsonMissing.of(), + @JsonProperty("member_count") + @ExcludeMissing + memberCount: JsonField = JsonMissing.of(), + @JsonProperty("message_count") + @ExcludeMissing + messageCount: JsonField = JsonMissing.of(), + @JsonProperty("outbound_count") + @ExcludeMissing + outboundCount: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this( + id, + contact, + groupId, + groupName, + inboundCount, + isGroup, + lastInboundTime, + lastMessage, + lastMessageTime, + lastOutboundTime, + memberCount, + messageCount, + outboundCount, + type, + mutableMapOf(), + ) + + /** + * Chat identifier (phone number, email, or group ID) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * Contact info (only for non-group chats) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun contact(): Optional = contact.getOptional("contact") + + /** + * Group ID (only for group chats) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun groupId(): Optional = groupId.getOptional("group_id") + + /** + * Group name (only for group chats) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun groupName(): Optional = groupName.getOptional("group_name") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun inboundCount(): Optional = inboundCount.getOptional("inbound_count") + + /** + * Whether this is a group chat + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun isGroup(): Optional = isGroup.getOptional("is_group") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun lastInboundTime(): Optional = lastInboundTime.getOptional("last_inbound_time") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun lastMessage(): Optional = lastMessage.getOptional("last_message") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun lastMessageTime(): Optional = lastMessageTime.getOptional("last_message_time") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun lastOutboundTime(): Optional = lastOutboundTime.getOptional("last_outbound_time") + + /** + * Number of members (only for group chats) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun memberCount(): Optional = memberCount.getOptional("member_count") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun messageCount(): Optional = messageCount.getOptional("message_count") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun outboundCount(): Optional = outboundCount.getOptional("outbound_count") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [contact]. + * + * Unlike [contact], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("contact") @ExcludeMissing fun _contact(): JsonField = contact + + /** + * Returns the raw JSON value of [groupId]. + * + * Unlike [groupId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_id") @ExcludeMissing fun _groupId(): JsonField = groupId + + /** + * Returns the raw JSON value of [groupName]. + * + * Unlike [groupName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_name") @ExcludeMissing fun _groupName(): JsonField = groupName + + /** + * Returns the raw JSON value of [inboundCount]. + * + * Unlike [inboundCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("inbound_count") + @ExcludeMissing + fun _inboundCount(): JsonField = inboundCount + + /** + * Returns the raw JSON value of [isGroup]. + * + * Unlike [isGroup], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("is_group") @ExcludeMissing fun _isGroup(): JsonField = isGroup + + /** + * Returns the raw JSON value of [lastInboundTime]. + * + * Unlike [lastInboundTime], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("last_inbound_time") + @ExcludeMissing + fun _lastInboundTime(): JsonField = lastInboundTime + + /** + * Returns the raw JSON value of [lastMessage]. + * + * Unlike [lastMessage], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("last_message") + @ExcludeMissing + fun _lastMessage(): JsonField = lastMessage + + /** + * Returns the raw JSON value of [lastMessageTime]. + * + * Unlike [lastMessageTime], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("last_message_time") + @ExcludeMissing + fun _lastMessageTime(): JsonField = lastMessageTime + + /** + * Returns the raw JSON value of [lastOutboundTime]. + * + * Unlike [lastOutboundTime], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("last_outbound_time") + @ExcludeMissing + fun _lastOutboundTime(): JsonField = lastOutboundTime + + /** + * Returns the raw JSON value of [memberCount]. + * + * Unlike [memberCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("member_count") + @ExcludeMissing + fun _memberCount(): JsonField = memberCount + + /** + * Returns the raw JSON value of [messageCount]. + * + * Unlike [messageCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("message_count") + @ExcludeMissing + fun _messageCount(): JsonField = messageCount + + /** + * Returns the raw JSON value of [outboundCount]. + * + * Unlike [outboundCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("outbound_count") + @ExcludeMissing + fun _outboundCount(): JsonField = outboundCount + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + @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 [Chat]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Chat]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var contact: JsonField = JsonMissing.of() + private var groupId: JsonField = JsonMissing.of() + private var groupName: JsonField = JsonMissing.of() + private var inboundCount: JsonField = JsonMissing.of() + private var isGroup: JsonField = JsonMissing.of() + private var lastInboundTime: JsonField = JsonMissing.of() + private var lastMessage: JsonField = JsonMissing.of() + private var lastMessageTime: JsonField = JsonMissing.of() + private var lastOutboundTime: JsonField = JsonMissing.of() + private var memberCount: JsonField = JsonMissing.of() + private var messageCount: JsonField = JsonMissing.of() + private var outboundCount: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(chat: Chat) = apply { + id = chat.id + contact = chat.contact + groupId = chat.groupId + groupName = chat.groupName + inboundCount = chat.inboundCount + isGroup = chat.isGroup + lastInboundTime = chat.lastInboundTime + lastMessage = chat.lastMessage + lastMessageTime = chat.lastMessageTime + lastOutboundTime = chat.lastOutboundTime + memberCount = chat.memberCount + messageCount = chat.messageCount + outboundCount = chat.outboundCount + type = chat.type + additionalProperties = chat.additionalProperties.toMutableMap() + } + + /** Chat identifier (phone number, email, or group ID) */ + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + /** Contact info (only for non-group chats) */ + fun contact(contact: Contact?) = contact(JsonField.ofNullable(contact)) + + /** Alias for calling [Builder.contact] with `contact.orElse(null)`. */ + fun contact(contact: Optional) = contact(contact.getOrNull()) + + /** + * Sets [Builder.contact] to an arbitrary JSON value. + * + * You should usually call [Builder.contact] with a well-typed [Contact] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun contact(contact: JsonField) = apply { this.contact = contact } + + /** Group ID (only for group chats) */ + fun groupId(groupId: String?) = groupId(JsonField.ofNullable(groupId)) + + /** Alias for calling [Builder.groupId] with `groupId.orElse(null)`. */ + fun groupId(groupId: Optional) = groupId(groupId.getOrNull()) + + /** + * Sets [Builder.groupId] to an arbitrary JSON value. + * + * You should usually call [Builder.groupId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun groupId(groupId: JsonField) = apply { this.groupId = groupId } + + /** Group name (only for group chats) */ + fun groupName(groupName: String?) = groupName(JsonField.ofNullable(groupName)) + + /** Alias for calling [Builder.groupName] with `groupName.orElse(null)`. */ + fun groupName(groupName: Optional) = groupName(groupName.getOrNull()) + + /** + * Sets [Builder.groupName] to an arbitrary JSON value. + * + * You should usually call [Builder.groupName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun groupName(groupName: JsonField) = apply { this.groupName = groupName } + + fun inboundCount(inboundCount: Long) = inboundCount(JsonField.of(inboundCount)) + + /** + * Sets [Builder.inboundCount] to an arbitrary JSON value. + * + * You should usually call [Builder.inboundCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun inboundCount(inboundCount: JsonField) = apply { + this.inboundCount = inboundCount + } + + /** Whether this is a group chat */ + fun isGroup(isGroup: Boolean) = isGroup(JsonField.of(isGroup)) + + /** + * Sets [Builder.isGroup] to an arbitrary JSON value. + * + * You should usually call [Builder.isGroup] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isGroup(isGroup: JsonField) = apply { this.isGroup = isGroup } + + fun lastInboundTime(lastInboundTime: Long?) = + lastInboundTime(JsonField.ofNullable(lastInboundTime)) + + /** + * Alias for [Builder.lastInboundTime]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun lastInboundTime(lastInboundTime: Long) = lastInboundTime(lastInboundTime as Long?) + + /** Alias for calling [Builder.lastInboundTime] with `lastInboundTime.orElse(null)`. */ + fun lastInboundTime(lastInboundTime: Optional) = + lastInboundTime(lastInboundTime.getOrNull()) + + /** + * Sets [Builder.lastInboundTime] to an arbitrary JSON value. + * + * You should usually call [Builder.lastInboundTime] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun lastInboundTime(lastInboundTime: JsonField) = apply { + this.lastInboundTime = lastInboundTime + } + + fun lastMessage(lastMessage: LastMessage) = lastMessage(JsonField.of(lastMessage)) + + /** + * Sets [Builder.lastMessage] to an arbitrary JSON value. + * + * You should usually call [Builder.lastMessage] with a well-typed [LastMessage] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun lastMessage(lastMessage: JsonField) = apply { + this.lastMessage = lastMessage + } + + fun lastMessageTime(lastMessageTime: Long) = + lastMessageTime(JsonField.of(lastMessageTime)) + + /** + * Sets [Builder.lastMessageTime] to an arbitrary JSON value. + * + * You should usually call [Builder.lastMessageTime] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun lastMessageTime(lastMessageTime: JsonField) = apply { + this.lastMessageTime = lastMessageTime + } + + fun lastOutboundTime(lastOutboundTime: Long?) = + lastOutboundTime(JsonField.ofNullable(lastOutboundTime)) + + /** + * Alias for [Builder.lastOutboundTime]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun lastOutboundTime(lastOutboundTime: Long) = + lastOutboundTime(lastOutboundTime as Long?) + + /** + * Alias for calling [Builder.lastOutboundTime] with `lastOutboundTime.orElse(null)`. + */ + fun lastOutboundTime(lastOutboundTime: Optional) = + lastOutboundTime(lastOutboundTime.getOrNull()) + + /** + * Sets [Builder.lastOutboundTime] to an arbitrary JSON value. + * + * You should usually call [Builder.lastOutboundTime] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun lastOutboundTime(lastOutboundTime: JsonField) = apply { + this.lastOutboundTime = lastOutboundTime + } + + /** Number of members (only for group chats) */ + fun memberCount(memberCount: Long) = memberCount(JsonField.of(memberCount)) + + /** + * Sets [Builder.memberCount] to an arbitrary JSON value. + * + * You should usually call [Builder.memberCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberCount(memberCount: JsonField) = apply { this.memberCount = memberCount } + + fun messageCount(messageCount: Long) = messageCount(JsonField.of(messageCount)) + + /** + * Sets [Builder.messageCount] to an arbitrary JSON value. + * + * You should usually call [Builder.messageCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun messageCount(messageCount: JsonField) = apply { + this.messageCount = messageCount + } + + fun outboundCount(outboundCount: Long) = outboundCount(JsonField.of(outboundCount)) + + /** + * Sets [Builder.outboundCount] to an arbitrary JSON value. + * + * You should usually call [Builder.outboundCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun outboundCount(outboundCount: JsonField) = apply { + this.outboundCount = outboundCount + } + + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonField) = apply { this.type = type } + + 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 [Chat]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Chat = + Chat( + id, + contact, + groupId, + groupName, + inboundCount, + isGroup, + lastInboundTime, + lastMessage, + lastMessageTime, + lastOutboundTime, + memberCount, + messageCount, + outboundCount, + type, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Chat = apply { + if (validated) { + return@apply + } + + id() + contact().ifPresent { it.validate() } + groupId() + groupName() + inboundCount() + isGroup() + lastInboundTime() + lastMessage().ifPresent { it.validate() } + lastMessageTime() + lastOutboundTime() + memberCount() + messageCount() + outboundCount() + type().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (id.asKnown().isPresent) 1 else 0) + + (contact.asKnown().getOrNull()?.validity() ?: 0) + + (if (groupId.asKnown().isPresent) 1 else 0) + + (if (groupName.asKnown().isPresent) 1 else 0) + + (if (inboundCount.asKnown().isPresent) 1 else 0) + + (if (isGroup.asKnown().isPresent) 1 else 0) + + (if (lastInboundTime.asKnown().isPresent) 1 else 0) + + (lastMessage.asKnown().getOrNull()?.validity() ?: 0) + + (if (lastMessageTime.asKnown().isPresent) 1 else 0) + + (if (lastOutboundTime.asKnown().isPresent) 1 else 0) + + (if (memberCount.asKnown().isPresent) 1 else 0) + + (if (messageCount.asKnown().isPresent) 1 else 0) + + (if (outboundCount.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + /** Contact info (only for non-group chats) */ + class Contact + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val contactId: JsonField, + private val identifier: JsonField, + private val name: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("contact_id") + @ExcludeMissing + contactId: JsonField = JsonMissing.of(), + @JsonProperty("identifier") + @ExcludeMissing + identifier: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(contactId, identifier, name, mutableMapOf()) + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun contactId(): Optional = contactId.getOptional("contact_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun identifier(): Optional = identifier.getOptional("identifier") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * Returns the raw JSON value of [contactId]. + * + * Unlike [contactId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("contact_id") + @ExcludeMissing + fun _contactId(): JsonField = contactId + + /** + * Returns the raw JSON value of [identifier]. + * + * Unlike [identifier], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("identifier") + @ExcludeMissing + fun _identifier(): JsonField = identifier + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + @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 [Contact]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Contact]. */ + class Builder internal constructor() { + + private var contactId: JsonField = JsonMissing.of() + private var identifier: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(contact: Contact) = apply { + contactId = contact.contactId + identifier = contact.identifier + name = contact.name + additionalProperties = contact.additionalProperties.toMutableMap() + } + + fun contactId(contactId: String) = contactId(JsonField.of(contactId)) + + /** + * Sets [Builder.contactId] to an arbitrary JSON value. + * + * You should usually call [Builder.contactId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun contactId(contactId: JsonField) = apply { this.contactId = contactId } + + fun identifier(identifier: String) = identifier(JsonField.of(identifier)) + + /** + * Sets [Builder.identifier] to an arbitrary JSON value. + * + * You should usually call [Builder.identifier] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun identifier(identifier: JsonField) = apply { + this.identifier = identifier + } + + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** Alias for calling [Builder.name] with `name.orElse(null)`. */ + fun name(name: Optional) = name(name.getOrNull()) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + 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 [Contact]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Contact = + Contact(contactId, identifier, name, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Contact = apply { + if (validated) { + return@apply + } + + contactId() + identifier() + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (contactId.asKnown().isPresent) 1 else 0) + + (if (identifier.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Contact && + contactId == other.contactId && + identifier == other.identifier && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(contactId, identifier, name, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Contact{contactId=$contactId, identifier=$identifier, name=$name, additionalProperties=$additionalProperties}" + } + + class Type @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val PHONE = of("phone") + + @JvmField val EMAIL = of("email") + + @JvmField val GROUP = of("group") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + PHONE, + EMAIL, + GROUP, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + PHONE, + EMAIL, + GROUP, + /** An enum member indicating that [Type] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + PHONE -> Value.PHONE + EMAIL -> Value.EMAIL + GROUP -> Value.GROUP + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + PHONE -> Known.PHONE + EMAIL -> Known.EMAIL + GROUP -> Known.GROUP + else -> throw BlooioInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + BlooioInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Chat && + id == other.id && + contact == other.contact && + groupId == other.groupId && + groupName == other.groupName && + inboundCount == other.inboundCount && + isGroup == other.isGroup && + lastInboundTime == other.lastInboundTime && + lastMessage == other.lastMessage && + lastMessageTime == other.lastMessageTime && + lastOutboundTime == other.lastOutboundTime && + memberCount == other.memberCount && + messageCount == other.messageCount && + outboundCount == other.outboundCount && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + contact, + groupId, + groupName, + inboundCount, + isGroup, + lastInboundTime, + lastMessage, + lastMessageTime, + lastOutboundTime, + memberCount, + messageCount, + outboundCount, + type, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Chat{id=$id, contact=$contact, groupId=$groupId, groupName=$groupName, inboundCount=$inboundCount, isGroup=$isGroup, lastInboundTime=$lastInboundTime, lastMessage=$lastMessage, lastMessageTime=$lastMessageTime, lastOutboundTime=$lastOutboundTime, memberCount=$memberCount, messageCount=$messageCount, outboundCount=$outboundCount, type=$type, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ChatListResponse && + chats == other.chats && + pagination == other.pagination && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(chats, pagination, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ChatListResponse{chats=$chats, pagination=$pagination, additionalProperties=$additionalProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatMarkAsReadParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatMarkAsReadParams.kt new file mode 100644 index 0000000..67be4e1 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatMarkAsReadParams.kt @@ -0,0 +1,229 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats + +import com.blooio.api.core.JsonValue +import com.blooio.api.core.Params +import com.blooio.api.core.http.Headers +import com.blooio.api.core.http.QueryParams +import com.blooio.api.core.toImmutable +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Mark all messages in a chat as read. This sends a read receipt to the sender. */ +class ChatMarkAsReadParams +private constructor( + private val chatId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, +) : Params { + + fun chatId(): Optional = Optional.ofNullable(chatId) + + /** 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(): ChatMarkAsReadParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ChatMarkAsReadParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ChatMarkAsReadParams]. */ + class Builder internal constructor() { + + private var chatId: 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(chatMarkAsReadParams: ChatMarkAsReadParams) = apply { + chatId = chatMarkAsReadParams.chatId + additionalHeaders = chatMarkAsReadParams.additionalHeaders.toBuilder() + additionalQueryParams = chatMarkAsReadParams.additionalQueryParams.toBuilder() + additionalBodyProperties = chatMarkAsReadParams.additionalBodyProperties.toMutableMap() + } + + fun chatId(chatId: String?) = apply { this.chatId = chatId } + + /** Alias for calling [Builder.chatId] with `chatId.orElse(null)`. */ + fun chatId(chatId: Optional) = chatId(chatId.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 [ChatMarkAsReadParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ChatMarkAsReadParams = + ChatMarkAsReadParams( + chatId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), + ) + } + + fun _body(): Optional> = + Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) + + fun _pathParam(index: Int): String = + when (index) { + 0 -> chatId ?: "" + 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 ChatMarkAsReadParams && + chatId == other.chatId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(chatId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "ChatMarkAsReadParams{chatId=$chatId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageGetStatusResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatMarkAsReadResponse.kt similarity index 69% rename from blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageGetStatusResponse.kt rename to blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatMarkAsReadResponse.kt index 4a7029d..b8539e0 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageGetStatusResponse.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatMarkAsReadResponse.kt @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. -package com.blooio.api.models.messages +package com.blooio.api.models.chats import com.blooio.api.core.Enum import com.blooio.api.core.ExcludeMissing @@ -17,38 +17,59 @@ import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull -class MessageGetStatusResponse +class ChatMarkAsReadResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val messageId: JsonField, + private val chatId: JsonField, + private val markedAt: JsonField, private val status: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("message_id") @ExcludeMissing messageId: JsonField = JsonMissing.of(), + @JsonProperty("chat_id") @ExcludeMissing chatId: JsonField = JsonMissing.of(), + @JsonProperty("marked_at") @ExcludeMissing markedAt: JsonField = JsonMissing.of(), @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), - ) : this(messageId, status, mutableMapOf()) + ) : this(chatId, markedAt, status, mutableMapOf()) /** + * Chat identifier + * * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun messageId(): Optional = messageId.getOptional("message_id") + fun chatId(): Optional = chatId.getOptional("chat_id") /** + * Timestamp when marked as read + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun markedAt(): Optional = markedAt.getOptional("marked_at") + + /** + * Read status + * * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun status(): Optional = status.getOptional("status") /** - * Returns the raw JSON value of [messageId]. + * Returns the raw JSON value of [chatId]. + * + * Unlike [chatId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("chat_id") @ExcludeMissing fun _chatId(): JsonField = chatId + + /** + * Returns the raw JSON value of [markedAt]. * - * Unlike [messageId], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [markedAt], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("message_id") @ExcludeMissing fun _messageId(): JsonField = messageId + @JsonProperty("marked_at") @ExcludeMissing fun _markedAt(): JsonField = markedAt /** * Returns the raw JSON value of [status]. @@ -71,35 +92,49 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [MessageGetStatusResponse]. */ + /** Returns a mutable builder for constructing an instance of [ChatMarkAsReadResponse]. */ @JvmStatic fun builder() = Builder() } - /** A builder for [MessageGetStatusResponse]. */ + /** A builder for [ChatMarkAsReadResponse]. */ class Builder internal constructor() { - private var messageId: JsonField = JsonMissing.of() + private var chatId: JsonField = JsonMissing.of() + private var markedAt: JsonField = JsonMissing.of() private var status: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(messageGetStatusResponse: MessageGetStatusResponse) = apply { - messageId = messageGetStatusResponse.messageId - status = messageGetStatusResponse.status - additionalProperties = messageGetStatusResponse.additionalProperties.toMutableMap() + internal fun from(chatMarkAsReadResponse: ChatMarkAsReadResponse) = apply { + chatId = chatMarkAsReadResponse.chatId + markedAt = chatMarkAsReadResponse.markedAt + status = chatMarkAsReadResponse.status + additionalProperties = chatMarkAsReadResponse.additionalProperties.toMutableMap() } - fun messageId(messageId: String) = messageId(JsonField.of(messageId)) + /** Chat identifier */ + fun chatId(chatId: String) = chatId(JsonField.of(chatId)) + + /** + * Sets [Builder.chatId] to an arbitrary JSON value. + * + * You should usually call [Builder.chatId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun chatId(chatId: JsonField) = apply { this.chatId = chatId } + + /** Timestamp when marked as read */ + fun markedAt(markedAt: Long) = markedAt(JsonField.of(markedAt)) /** - * Sets [Builder.messageId] to an arbitrary JSON value. + * Sets [Builder.markedAt] to an arbitrary JSON value. * - * You should usually call [Builder.messageId] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. + * You should usually call [Builder.markedAt] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun messageId(messageId: JsonField) = apply { this.messageId = messageId } + fun markedAt(markedAt: JsonField) = apply { this.markedAt = markedAt } + /** Read status */ fun status(status: Status) = status(JsonField.of(status)) /** @@ -130,22 +165,23 @@ private constructor( } /** - * Returns an immutable instance of [MessageGetStatusResponse]. + * Returns an immutable instance of [ChatMarkAsReadResponse]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): MessageGetStatusResponse = - MessageGetStatusResponse(messageId, status, additionalProperties.toMutableMap()) + fun build(): ChatMarkAsReadResponse = + ChatMarkAsReadResponse(chatId, markedAt, status, additionalProperties.toMutableMap()) } private var validated: Boolean = false - fun validate(): MessageGetStatusResponse = apply { + fun validate(): ChatMarkAsReadResponse = apply { if (validated) { return@apply } - messageId() + chatId() + markedAt() status().ifPresent { it.validate() } validated = true } @@ -165,9 +201,11 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (messageId.asKnown().isPresent) 1 else 0) + + (if (chatId.asKnown().isPresent) 1 else 0) + + (if (markedAt.asKnown().isPresent) 1 else 0) + (status.asKnown().getOrNull()?.validity() ?: 0) + /** Read status */ class Status @JsonCreator private constructor(private val value: JsonField) : Enum { /** @@ -182,32 +220,14 @@ private constructor( companion object { - @JvmField val PENDING = of("pending") - - @JvmField val QUEUED = of("queued") - - @JvmField val SENT = of("sent") - - @JvmField val DELIVERED = of("delivered") - - @JvmField val FAILED = of("failed") - - @JvmField val CANCELLED = of("cancelled") - - @JvmField val CANCELLATION_REQUESTED = of("cancellation_requested") + @JvmField val READ = of("read") @JvmStatic fun of(value: String) = Status(JsonField.of(value)) } /** An enum containing [Status]'s known values. */ enum class Known { - PENDING, - QUEUED, - SENT, - DELIVERED, - FAILED, - CANCELLED, - CANCELLATION_REQUESTED, + READ } /** @@ -220,13 +240,7 @@ private constructor( * - It was constructed with an arbitrary value using the [of] method. */ enum class Value { - PENDING, - QUEUED, - SENT, - DELIVERED, - FAILED, - CANCELLED, - CANCELLATION_REQUESTED, + READ, /** An enum member indicating that [Status] was instantiated with an unknown value. */ _UNKNOWN, } @@ -240,13 +254,7 @@ private constructor( */ fun value(): Value = when (this) { - PENDING -> Value.PENDING - QUEUED -> Value.QUEUED - SENT -> Value.SENT - DELIVERED -> Value.DELIVERED - FAILED -> Value.FAILED - CANCELLED -> Value.CANCELLED - CANCELLATION_REQUESTED -> Value.CANCELLATION_REQUESTED + READ -> Value.READ else -> Value._UNKNOWN } @@ -261,13 +269,7 @@ private constructor( */ fun known(): Known = when (this) { - PENDING -> Known.PENDING - QUEUED -> Known.QUEUED - SENT -> Known.SENT - DELIVERED -> Known.DELIVERED - FAILED -> Known.FAILED - CANCELLED -> Known.CANCELLED - CANCELLATION_REQUESTED -> Known.CANCELLATION_REQUESTED + READ -> Known.READ else -> throw BlooioInvalidDataException("Unknown Status: $value") } @@ -328,16 +330,19 @@ private constructor( return true } - return other is MessageGetStatusResponse && - messageId == other.messageId && + return other is ChatMarkAsReadResponse && + chatId == other.chatId && + markedAt == other.markedAt && status == other.status && additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(messageId, status, additionalProperties) } + private val hashCode: Int by lazy { + Objects.hash(chatId, markedAt, status, additionalProperties) + } override fun hashCode(): Int = hashCode override fun toString() = - "MessageGetStatusResponse{messageId=$messageId, status=$status, additionalProperties=$additionalProperties}" + "ChatMarkAsReadResponse{chatId=$chatId, markedAt=$markedAt, status=$status, additionalProperties=$additionalProperties}" } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatRetrieveParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatRetrieveParams.kt new file mode 100644 index 0000000..6a1740a --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatRetrieveParams.kt @@ -0,0 +1,189 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats + +import com.blooio.api.core.Params +import com.blooio.api.core.http.Headers +import com.blooio.api.core.http.QueryParams +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Get details for a specific conversation. */ +class ChatRetrieveParams +private constructor( + private val chatId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun chatId(): Optional = Optional.ofNullable(chatId) + + /** 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(): ChatRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ChatRetrieveParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ChatRetrieveParams]. */ + class Builder internal constructor() { + + private var chatId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(chatRetrieveParams: ChatRetrieveParams) = apply { + chatId = chatRetrieveParams.chatId + additionalHeaders = chatRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = chatRetrieveParams.additionalQueryParams.toBuilder() + } + + fun chatId(chatId: String?) = apply { this.chatId = chatId } + + /** Alias for calling [Builder.chatId] with `chatId.orElse(null)`. */ + fun chatId(chatId: Optional) = chatId(chatId.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) + } + + /** + * Returns an immutable instance of [ChatRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ChatRetrieveParams = + ChatRetrieveParams(chatId, additionalHeaders.build(), additionalQueryParams.build()) + } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> chatId ?: "" + 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 ChatRetrieveParams && + chatId == other.chatId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(chatId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ChatRetrieveParams{chatId=$chatId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatRetrieveResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatRetrieveResponse.kt new file mode 100644 index 0000000..2dc1e56 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatRetrieveResponse.kt @@ -0,0 +1,1086 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats + +import com.blooio.api.core.Enum +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class ChatRetrieveResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val id: JsonField, + private val contact: JsonField, + private val firstMessageTime: JsonField, + private val groupId: JsonField, + private val groupName: JsonField, + private val inboundCount: JsonField, + private val isGroup: JsonField, + private val lastInboundTime: JsonField, + private val lastMessage: JsonField, + private val lastMessageTime: JsonField, + private val lastOutboundTime: JsonField, + private val memberCount: JsonField, + private val messageCount: JsonField, + private val outboundCount: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("contact") @ExcludeMissing contact: JsonField = JsonMissing.of(), + @JsonProperty("first_message_time") + @ExcludeMissing + firstMessageTime: JsonField = JsonMissing.of(), + @JsonProperty("group_id") @ExcludeMissing groupId: JsonField = JsonMissing.of(), + @JsonProperty("group_name") @ExcludeMissing groupName: JsonField = JsonMissing.of(), + @JsonProperty("inbound_count") + @ExcludeMissing + inboundCount: JsonField = JsonMissing.of(), + @JsonProperty("is_group") @ExcludeMissing isGroup: JsonField = JsonMissing.of(), + @JsonProperty("last_inbound_time") + @ExcludeMissing + lastInboundTime: JsonField = JsonMissing.of(), + @JsonProperty("last_message") + @ExcludeMissing + lastMessage: JsonField = JsonMissing.of(), + @JsonProperty("last_message_time") + @ExcludeMissing + lastMessageTime: JsonField = JsonMissing.of(), + @JsonProperty("last_outbound_time") + @ExcludeMissing + lastOutboundTime: JsonField = JsonMissing.of(), + @JsonProperty("member_count") + @ExcludeMissing + memberCount: JsonField = JsonMissing.of(), + @JsonProperty("message_count") + @ExcludeMissing + messageCount: JsonField = JsonMissing.of(), + @JsonProperty("outbound_count") + @ExcludeMissing + outboundCount: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this( + id, + contact, + firstMessageTime, + groupId, + groupName, + inboundCount, + isGroup, + lastInboundTime, + lastMessage, + lastMessageTime, + lastOutboundTime, + memberCount, + messageCount, + outboundCount, + type, + mutableMapOf(), + ) + + /** + * Chat identifier (phone number, email, or group ID) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * Contact info (only for non-group chats) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun contact(): Optional = contact.getOptional("contact") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun firstMessageTime(): Optional = firstMessageTime.getOptional("first_message_time") + + /** + * Group ID (only for group chats) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun groupId(): Optional = groupId.getOptional("group_id") + + /** + * Group name (only for group chats) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun groupName(): Optional = groupName.getOptional("group_name") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun inboundCount(): Optional = inboundCount.getOptional("inbound_count") + + /** + * Whether this is a group chat + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun isGroup(): Optional = isGroup.getOptional("is_group") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun lastInboundTime(): Optional = lastInboundTime.getOptional("last_inbound_time") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun lastMessage(): Optional = lastMessage.getOptional("last_message") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun lastMessageTime(): Optional = lastMessageTime.getOptional("last_message_time") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun lastOutboundTime(): Optional = lastOutboundTime.getOptional("last_outbound_time") + + /** + * Number of members (only for group chats) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun memberCount(): Optional = memberCount.getOptional("member_count") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun messageCount(): Optional = messageCount.getOptional("message_count") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun outboundCount(): Optional = outboundCount.getOptional("outbound_count") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [contact]. + * + * Unlike [contact], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("contact") @ExcludeMissing fun _contact(): JsonField = contact + + /** + * Returns the raw JSON value of [firstMessageTime]. + * + * Unlike [firstMessageTime], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("first_message_time") + @ExcludeMissing + fun _firstMessageTime(): JsonField = firstMessageTime + + /** + * Returns the raw JSON value of [groupId]. + * + * Unlike [groupId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_id") @ExcludeMissing fun _groupId(): JsonField = groupId + + /** + * Returns the raw JSON value of [groupName]. + * + * Unlike [groupName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_name") @ExcludeMissing fun _groupName(): JsonField = groupName + + /** + * Returns the raw JSON value of [inboundCount]. + * + * Unlike [inboundCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("inbound_count") + @ExcludeMissing + fun _inboundCount(): JsonField = inboundCount + + /** + * Returns the raw JSON value of [isGroup]. + * + * Unlike [isGroup], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("is_group") @ExcludeMissing fun _isGroup(): JsonField = isGroup + + /** + * Returns the raw JSON value of [lastInboundTime]. + * + * Unlike [lastInboundTime], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("last_inbound_time") + @ExcludeMissing + fun _lastInboundTime(): JsonField = lastInboundTime + + /** + * Returns the raw JSON value of [lastMessage]. + * + * Unlike [lastMessage], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("last_message") + @ExcludeMissing + fun _lastMessage(): JsonField = lastMessage + + /** + * Returns the raw JSON value of [lastMessageTime]. + * + * Unlike [lastMessageTime], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("last_message_time") + @ExcludeMissing + fun _lastMessageTime(): JsonField = lastMessageTime + + /** + * Returns the raw JSON value of [lastOutboundTime]. + * + * Unlike [lastOutboundTime], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("last_outbound_time") + @ExcludeMissing + fun _lastOutboundTime(): JsonField = lastOutboundTime + + /** + * Returns the raw JSON value of [memberCount]. + * + * Unlike [memberCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("member_count") @ExcludeMissing fun _memberCount(): JsonField = memberCount + + /** + * Returns the raw JSON value of [messageCount]. + * + * Unlike [messageCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message_count") + @ExcludeMissing + fun _messageCount(): JsonField = messageCount + + /** + * Returns the raw JSON value of [outboundCount]. + * + * Unlike [outboundCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("outbound_count") + @ExcludeMissing + fun _outboundCount(): JsonField = outboundCount + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + @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 [ChatRetrieveResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ChatRetrieveResponse]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var contact: JsonField = JsonMissing.of() + private var firstMessageTime: JsonField = JsonMissing.of() + private var groupId: JsonField = JsonMissing.of() + private var groupName: JsonField = JsonMissing.of() + private var inboundCount: JsonField = JsonMissing.of() + private var isGroup: JsonField = JsonMissing.of() + private var lastInboundTime: JsonField = JsonMissing.of() + private var lastMessage: JsonField = JsonMissing.of() + private var lastMessageTime: JsonField = JsonMissing.of() + private var lastOutboundTime: JsonField = JsonMissing.of() + private var memberCount: JsonField = JsonMissing.of() + private var messageCount: JsonField = JsonMissing.of() + private var outboundCount: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(chatRetrieveResponse: ChatRetrieveResponse) = apply { + id = chatRetrieveResponse.id + contact = chatRetrieveResponse.contact + firstMessageTime = chatRetrieveResponse.firstMessageTime + groupId = chatRetrieveResponse.groupId + groupName = chatRetrieveResponse.groupName + inboundCount = chatRetrieveResponse.inboundCount + isGroup = chatRetrieveResponse.isGroup + lastInboundTime = chatRetrieveResponse.lastInboundTime + lastMessage = chatRetrieveResponse.lastMessage + lastMessageTime = chatRetrieveResponse.lastMessageTime + lastOutboundTime = chatRetrieveResponse.lastOutboundTime + memberCount = chatRetrieveResponse.memberCount + messageCount = chatRetrieveResponse.messageCount + outboundCount = chatRetrieveResponse.outboundCount + type = chatRetrieveResponse.type + additionalProperties = chatRetrieveResponse.additionalProperties.toMutableMap() + } + + /** Chat identifier (phone number, email, or group ID) */ + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun id(id: JsonField) = apply { this.id = id } + + /** Contact info (only for non-group chats) */ + fun contact(contact: Contact?) = contact(JsonField.ofNullable(contact)) + + /** Alias for calling [Builder.contact] with `contact.orElse(null)`. */ + fun contact(contact: Optional) = contact(contact.getOrNull()) + + /** + * Sets [Builder.contact] to an arbitrary JSON value. + * + * You should usually call [Builder.contact] with a well-typed [Contact] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun contact(contact: JsonField) = apply { this.contact = contact } + + fun firstMessageTime(firstMessageTime: Long) = + firstMessageTime(JsonField.of(firstMessageTime)) + + /** + * Sets [Builder.firstMessageTime] to an arbitrary JSON value. + * + * You should usually call [Builder.firstMessageTime] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun firstMessageTime(firstMessageTime: JsonField) = apply { + this.firstMessageTime = firstMessageTime + } + + /** Group ID (only for group chats) */ + fun groupId(groupId: String?) = groupId(JsonField.ofNullable(groupId)) + + /** Alias for calling [Builder.groupId] with `groupId.orElse(null)`. */ + fun groupId(groupId: Optional) = groupId(groupId.getOrNull()) + + /** + * Sets [Builder.groupId] to an arbitrary JSON value. + * + * You should usually call [Builder.groupId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun groupId(groupId: JsonField) = apply { this.groupId = groupId } + + /** Group name (only for group chats) */ + fun groupName(groupName: String?) = groupName(JsonField.ofNullable(groupName)) + + /** Alias for calling [Builder.groupName] with `groupName.orElse(null)`. */ + fun groupName(groupName: Optional) = groupName(groupName.getOrNull()) + + /** + * Sets [Builder.groupName] to an arbitrary JSON value. + * + * You should usually call [Builder.groupName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun groupName(groupName: JsonField) = apply { this.groupName = groupName } + + fun inboundCount(inboundCount: Long) = inboundCount(JsonField.of(inboundCount)) + + /** + * Sets [Builder.inboundCount] to an arbitrary JSON value. + * + * You should usually call [Builder.inboundCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun inboundCount(inboundCount: JsonField) = apply { this.inboundCount = inboundCount } + + /** Whether this is a group chat */ + fun isGroup(isGroup: Boolean) = isGroup(JsonField.of(isGroup)) + + /** + * Sets [Builder.isGroup] to an arbitrary JSON value. + * + * You should usually call [Builder.isGroup] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun isGroup(isGroup: JsonField) = apply { this.isGroup = isGroup } + + fun lastInboundTime(lastInboundTime: Long?) = + lastInboundTime(JsonField.ofNullable(lastInboundTime)) + + /** + * Alias for [Builder.lastInboundTime]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun lastInboundTime(lastInboundTime: Long) = lastInboundTime(lastInboundTime as Long?) + + /** Alias for calling [Builder.lastInboundTime] with `lastInboundTime.orElse(null)`. */ + fun lastInboundTime(lastInboundTime: Optional) = + lastInboundTime(lastInboundTime.getOrNull()) + + /** + * Sets [Builder.lastInboundTime] to an arbitrary JSON value. + * + * You should usually call [Builder.lastInboundTime] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun lastInboundTime(lastInboundTime: JsonField) = apply { + this.lastInboundTime = lastInboundTime + } + + fun lastMessage(lastMessage: LastMessage) = lastMessage(JsonField.of(lastMessage)) + + /** + * Sets [Builder.lastMessage] to an arbitrary JSON value. + * + * You should usually call [Builder.lastMessage] with a well-typed [LastMessage] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun lastMessage(lastMessage: JsonField) = apply { + this.lastMessage = lastMessage + } + + fun lastMessageTime(lastMessageTime: Long) = lastMessageTime(JsonField.of(lastMessageTime)) + + /** + * Sets [Builder.lastMessageTime] to an arbitrary JSON value. + * + * You should usually call [Builder.lastMessageTime] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun lastMessageTime(lastMessageTime: JsonField) = apply { + this.lastMessageTime = lastMessageTime + } + + fun lastOutboundTime(lastOutboundTime: Long?) = + lastOutboundTime(JsonField.ofNullable(lastOutboundTime)) + + /** + * Alias for [Builder.lastOutboundTime]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun lastOutboundTime(lastOutboundTime: Long) = lastOutboundTime(lastOutboundTime as Long?) + + /** Alias for calling [Builder.lastOutboundTime] with `lastOutboundTime.orElse(null)`. */ + fun lastOutboundTime(lastOutboundTime: Optional) = + lastOutboundTime(lastOutboundTime.getOrNull()) + + /** + * Sets [Builder.lastOutboundTime] to an arbitrary JSON value. + * + * You should usually call [Builder.lastOutboundTime] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun lastOutboundTime(lastOutboundTime: JsonField) = apply { + this.lastOutboundTime = lastOutboundTime + } + + /** Number of members (only for group chats) */ + fun memberCount(memberCount: Long) = memberCount(JsonField.of(memberCount)) + + /** + * Sets [Builder.memberCount] to an arbitrary JSON value. + * + * You should usually call [Builder.memberCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun memberCount(memberCount: JsonField) = apply { this.memberCount = memberCount } + + fun messageCount(messageCount: Long) = messageCount(JsonField.of(messageCount)) + + /** + * Sets [Builder.messageCount] to an arbitrary JSON value. + * + * You should usually call [Builder.messageCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun messageCount(messageCount: JsonField) = apply { this.messageCount = messageCount } + + fun outboundCount(outboundCount: Long) = outboundCount(JsonField.of(outboundCount)) + + /** + * Sets [Builder.outboundCount] to an arbitrary JSON value. + * + * You should usually call [Builder.outboundCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun outboundCount(outboundCount: JsonField) = apply { + this.outboundCount = outboundCount + } + + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + 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 [ChatRetrieveResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ChatRetrieveResponse = + ChatRetrieveResponse( + id, + contact, + firstMessageTime, + groupId, + groupName, + inboundCount, + isGroup, + lastInboundTime, + lastMessage, + lastMessageTime, + lastOutboundTime, + memberCount, + messageCount, + outboundCount, + type, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ChatRetrieveResponse = apply { + if (validated) { + return@apply + } + + id() + contact().ifPresent { it.validate() } + firstMessageTime() + groupId() + groupName() + inboundCount() + isGroup() + lastInboundTime() + lastMessage().ifPresent { it.validate() } + lastMessageTime() + lastOutboundTime() + memberCount() + messageCount() + outboundCount() + type().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (id.asKnown().isPresent) 1 else 0) + + (contact.asKnown().getOrNull()?.validity() ?: 0) + + (if (firstMessageTime.asKnown().isPresent) 1 else 0) + + (if (groupId.asKnown().isPresent) 1 else 0) + + (if (groupName.asKnown().isPresent) 1 else 0) + + (if (inboundCount.asKnown().isPresent) 1 else 0) + + (if (isGroup.asKnown().isPresent) 1 else 0) + + (if (lastInboundTime.asKnown().isPresent) 1 else 0) + + (lastMessage.asKnown().getOrNull()?.validity() ?: 0) + + (if (lastMessageTime.asKnown().isPresent) 1 else 0) + + (if (lastOutboundTime.asKnown().isPresent) 1 else 0) + + (if (memberCount.asKnown().isPresent) 1 else 0) + + (if (messageCount.asKnown().isPresent) 1 else 0) + + (if (outboundCount.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + /** Contact info (only for non-group chats) */ + class Contact + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val contactId: JsonField, + private val identifier: JsonField, + private val name: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("contact_id") + @ExcludeMissing + contactId: JsonField = JsonMissing.of(), + @JsonProperty("identifier") + @ExcludeMissing + identifier: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(contactId, identifier, name, mutableMapOf()) + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun contactId(): Optional = contactId.getOptional("contact_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun identifier(): Optional = identifier.getOptional("identifier") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * Returns the raw JSON value of [contactId]. + * + * Unlike [contactId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("contact_id") @ExcludeMissing fun _contactId(): JsonField = contactId + + /** + * Returns the raw JSON value of [identifier]. + * + * Unlike [identifier], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("identifier") + @ExcludeMissing + fun _identifier(): JsonField = identifier + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + @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 [Contact]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Contact]. */ + class Builder internal constructor() { + + private var contactId: JsonField = JsonMissing.of() + private var identifier: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(contact: Contact) = apply { + contactId = contact.contactId + identifier = contact.identifier + name = contact.name + additionalProperties = contact.additionalProperties.toMutableMap() + } + + fun contactId(contactId: String) = contactId(JsonField.of(contactId)) + + /** + * Sets [Builder.contactId] to an arbitrary JSON value. + * + * You should usually call [Builder.contactId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun contactId(contactId: JsonField) = apply { this.contactId = contactId } + + fun identifier(identifier: String) = identifier(JsonField.of(identifier)) + + /** + * Sets [Builder.identifier] to an arbitrary JSON value. + * + * You should usually call [Builder.identifier] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun identifier(identifier: JsonField) = apply { this.identifier = identifier } + + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** Alias for calling [Builder.name] with `name.orElse(null)`. */ + fun name(name: Optional) = name(name.getOrNull()) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + 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 [Contact]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Contact = + Contact(contactId, identifier, name, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Contact = apply { + if (validated) { + return@apply + } + + contactId() + identifier() + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (contactId.asKnown().isPresent) 1 else 0) + + (if (identifier.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Contact && + contactId == other.contactId && + identifier == other.identifier && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(contactId, identifier, name, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Contact{contactId=$contactId, identifier=$identifier, name=$name, additionalProperties=$additionalProperties}" + } + + class Type @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val PHONE = of("phone") + + @JvmField val EMAIL = of("email") + + @JvmField val GROUP = of("group") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + PHONE, + EMAIL, + GROUP, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + PHONE, + EMAIL, + GROUP, + /** An enum member indicating that [Type] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + PHONE -> Value.PHONE + EMAIL -> Value.EMAIL + GROUP -> Value.GROUP + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + PHONE -> Known.PHONE + EMAIL -> Known.EMAIL + GROUP -> Known.GROUP + else -> throw BlooioInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ChatRetrieveResponse && + id == other.id && + contact == other.contact && + firstMessageTime == other.firstMessageTime && + groupId == other.groupId && + groupName == other.groupName && + inboundCount == other.inboundCount && + isGroup == other.isGroup && + lastInboundTime == other.lastInboundTime && + lastMessage == other.lastMessage && + lastMessageTime == other.lastMessageTime && + lastOutboundTime == other.lastOutboundTime && + memberCount == other.memberCount && + messageCount == other.messageCount && + outboundCount == other.outboundCount && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + contact, + firstMessageTime, + groupId, + groupName, + inboundCount, + isGroup, + lastInboundTime, + lastMessage, + lastMessageTime, + lastOutboundTime, + memberCount, + messageCount, + outboundCount, + type, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ChatRetrieveResponse{id=$id, contact=$contact, firstMessageTime=$firstMessageTime, groupId=$groupId, groupName=$groupName, inboundCount=$inboundCount, isGroup=$isGroup, lastInboundTime=$lastInboundTime, lastMessage=$lastMessage, lastMessageTime=$lastMessageTime, lastOutboundTime=$lastOutboundTime, memberCount=$memberCount, messageCount=$messageCount, outboundCount=$outboundCount, type=$type, additionalProperties=$additionalProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatShareContactCardParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatShareContactCardParams.kt new file mode 100644 index 0000000..1c9208e --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatShareContactCardParams.kt @@ -0,0 +1,236 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats + +import com.blooio.api.core.JsonValue +import com.blooio.api.core.Params +import com.blooio.api.core.http.Headers +import com.blooio.api.core.http.QueryParams +import com.blooio.api.core.toImmutable +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Stage the contact card (Name & Photo) for sharing in a chat. The contact card will be piggybacked + * onto the next outgoing message (text or attachment) sent to this chat. This is idempotent — + * calling it multiple times is harmless. + */ +class ChatShareContactCardParams +private constructor( + private val chatId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, +) : Params { + + fun chatId(): Optional = Optional.ofNullable(chatId) + + /** 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(): ChatShareContactCardParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of [ChatShareContactCardParams]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ChatShareContactCardParams]. */ + class Builder internal constructor() { + + private var chatId: 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(chatShareContactCardParams: ChatShareContactCardParams) = apply { + chatId = chatShareContactCardParams.chatId + additionalHeaders = chatShareContactCardParams.additionalHeaders.toBuilder() + additionalQueryParams = chatShareContactCardParams.additionalQueryParams.toBuilder() + additionalBodyProperties = + chatShareContactCardParams.additionalBodyProperties.toMutableMap() + } + + fun chatId(chatId: String?) = apply { this.chatId = chatId } + + /** Alias for calling [Builder.chatId] with `chatId.orElse(null)`. */ + fun chatId(chatId: Optional) = chatId(chatId.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 [ChatShareContactCardParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ChatShareContactCardParams = + ChatShareContactCardParams( + chatId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), + ) + } + + fun _body(): Optional> = + Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) + + fun _pathParam(index: Int): String = + when (index) { + 0 -> chatId ?: "" + 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 ChatShareContactCardParams && + chatId == other.chatId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(chatId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "ChatShareContactCardParams{chatId=$chatId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatShareContactCardResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatShareContactCardResponse.kt new file mode 100644 index 0000000..10e4993 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/ChatShareContactCardResponse.kt @@ -0,0 +1,227 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats + +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional + +class ChatShareContactCardResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val chatId: JsonField, + private val message: JsonField, + private val success: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("chat_id") @ExcludeMissing chatId: JsonField = JsonMissing.of(), + @JsonProperty("message") @ExcludeMissing message: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + ) : this(chatId, message, success, mutableMapOf()) + + /** + * Normalized chat identifier + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun chatId(): Optional = chatId.getOptional("chat_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun message(): Optional = message.getOptional("message") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun success(): Optional = success.getOptional("success") + + /** + * Returns the raw JSON value of [chatId]. + * + * Unlike [chatId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("chat_id") @ExcludeMissing fun _chatId(): JsonField = chatId + + /** + * Returns the raw JSON value of [message]. + * + * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + + @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 [ChatShareContactCardResponse]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ChatShareContactCardResponse]. */ + class Builder internal constructor() { + + private var chatId: JsonField = JsonMissing.of() + private var message: JsonField = JsonMissing.of() + private var success: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(chatShareContactCardResponse: ChatShareContactCardResponse) = apply { + chatId = chatShareContactCardResponse.chatId + message = chatShareContactCardResponse.message + success = chatShareContactCardResponse.success + additionalProperties = chatShareContactCardResponse.additionalProperties.toMutableMap() + } + + /** Normalized chat identifier */ + fun chatId(chatId: String) = chatId(JsonField.of(chatId)) + + /** + * Sets [Builder.chatId] to an arbitrary JSON value. + * + * You should usually call [Builder.chatId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun chatId(chatId: JsonField) = apply { this.chatId = chatId } + + fun message(message: String) = message(JsonField.of(message)) + + /** + * Sets [Builder.message] to an arbitrary JSON value. + * + * You should usually call [Builder.message] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun message(message: JsonField) = apply { this.message = message } + + fun success(success: Boolean) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + + 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 [ChatShareContactCardResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ChatShareContactCardResponse = + ChatShareContactCardResponse( + chatId, + message, + success, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ChatShareContactCardResponse = apply { + if (validated) { + return@apply + } + + chatId() + message() + success() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (chatId.asKnown().isPresent) 1 else 0) + + (if (message.asKnown().isPresent) 1 else 0) + + (if (success.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ChatShareContactCardResponse && + chatId == other.chatId && + message == other.message && + success == other.success && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(chatId, message, success, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ChatShareContactCardResponse{chatId=$chatId, message=$message, success=$success, additionalProperties=$additionalProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/LastMessage.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/LastMessage.kt new file mode 100644 index 0000000..e062062 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/LastMessage.kt @@ -0,0 +1,383 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats + +import com.blooio.api.core.Enum +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class LastMessage +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val direction: JsonField, + private val messageId: JsonField, + private val text: JsonField, + private val timeSent: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("direction") + @ExcludeMissing + direction: JsonField = JsonMissing.of(), + @JsonProperty("message_id") @ExcludeMissing messageId: JsonField = JsonMissing.of(), + @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), + @JsonProperty("time_sent") @ExcludeMissing timeSent: JsonField = JsonMissing.of(), + ) : this(direction, messageId, text, timeSent, mutableMapOf()) + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun direction(): Optional = direction.getOptional("direction") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun messageId(): Optional = messageId.getOptional("message_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun text(): Optional = text.getOptional("text") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun timeSent(): Optional = timeSent.getOptional("time_sent") + + /** + * Returns the raw JSON value of [direction]. + * + * Unlike [direction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("direction") @ExcludeMissing fun _direction(): JsonField = direction + + /** + * Returns the raw JSON value of [messageId]. + * + * Unlike [messageId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message_id") @ExcludeMissing fun _messageId(): JsonField = messageId + + /** + * Returns the raw JSON value of [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text + + /** + * Returns the raw JSON value of [timeSent]. + * + * Unlike [timeSent], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("time_sent") @ExcludeMissing fun _timeSent(): JsonField = timeSent + + @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 [LastMessage]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [LastMessage]. */ + class Builder internal constructor() { + + private var direction: JsonField = JsonMissing.of() + private var messageId: JsonField = JsonMissing.of() + private var text: JsonField = JsonMissing.of() + private var timeSent: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(lastMessage: LastMessage) = apply { + direction = lastMessage.direction + messageId = lastMessage.messageId + text = lastMessage.text + timeSent = lastMessage.timeSent + additionalProperties = lastMessage.additionalProperties.toMutableMap() + } + + fun direction(direction: Direction) = direction(JsonField.of(direction)) + + /** + * Sets [Builder.direction] to an arbitrary JSON value. + * + * You should usually call [Builder.direction] with a well-typed [Direction] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun direction(direction: JsonField) = apply { this.direction = direction } + + fun messageId(messageId: String) = messageId(JsonField.of(messageId)) + + /** + * Sets [Builder.messageId] to an arbitrary JSON value. + * + * You should usually call [Builder.messageId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun messageId(messageId: JsonField) = apply { this.messageId = messageId } + + fun text(text: String?) = text(JsonField.ofNullable(text)) + + /** Alias for calling [Builder.text] with `text.orElse(null)`. */ + fun text(text: Optional) = text(text.getOrNull()) + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun text(text: JsonField) = apply { this.text = text } + + fun timeSent(timeSent: Long) = timeSent(JsonField.of(timeSent)) + + /** + * Sets [Builder.timeSent] to an arbitrary JSON value. + * + * You should usually call [Builder.timeSent] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun timeSent(timeSent: JsonField) = apply { this.timeSent = timeSent } + + 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 [LastMessage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): LastMessage = + LastMessage(direction, messageId, text, timeSent, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): LastMessage = apply { + if (validated) { + return@apply + } + + direction().ifPresent { it.validate() } + messageId() + text() + timeSent() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 = + (direction.asKnown().getOrNull()?.validity() ?: 0) + + (if (messageId.asKnown().isPresent) 1 else 0) + + (if (text.asKnown().isPresent) 1 else 0) + + (if (timeSent.asKnown().isPresent) 1 else 0) + + class Direction @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val INBOUND = of("inbound") + + @JvmField val OUTBOUND = of("outbound") + + @JvmStatic fun of(value: String) = Direction(JsonField.of(value)) + } + + /** An enum containing [Direction]'s known values. */ + enum class Known { + INBOUND, + OUTBOUND, + } + + /** + * An enum containing [Direction]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Direction] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + INBOUND, + OUTBOUND, + /** + * An enum member indicating that [Direction] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + INBOUND -> Value.INBOUND + OUTBOUND -> Value.OUTBOUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + INBOUND -> Known.INBOUND + OUTBOUND -> Known.OUTBOUND + else -> throw BlooioInvalidDataException("Unknown Direction: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Direction = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Direction && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is LastMessage && + direction == other.direction && + messageId == other.messageId && + text == other.text && + timeSent == other.timeSent && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(direction, messageId, text, timeSent, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "LastMessage{direction=$direction, messageId=$messageId, text=$text, timeSent=$timeSent, additionalProperties=$additionalProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/BackgroundRemoveParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/BackgroundRemoveParams.kt new file mode 100644 index 0000000..eceee5b --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/BackgroundRemoveParams.kt @@ -0,0 +1,230 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.background + +import com.blooio.api.core.JsonValue +import com.blooio.api.core.Params +import com.blooio.api.core.http.Headers +import com.blooio.api.core.http.QueryParams +import com.blooio.api.core.toImmutable +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Remove the background image from a conversation, reverting to the default appearance. */ +class BackgroundRemoveParams +private constructor( + private val chatId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, +) : Params { + + fun chatId(): Optional = Optional.ofNullable(chatId) + + /** 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(): BackgroundRemoveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [BackgroundRemoveParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BackgroundRemoveParams]. */ + class Builder internal constructor() { + + private var chatId: 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(backgroundRemoveParams: BackgroundRemoveParams) = apply { + chatId = backgroundRemoveParams.chatId + additionalHeaders = backgroundRemoveParams.additionalHeaders.toBuilder() + additionalQueryParams = backgroundRemoveParams.additionalQueryParams.toBuilder() + additionalBodyProperties = + backgroundRemoveParams.additionalBodyProperties.toMutableMap() + } + + fun chatId(chatId: String?) = apply { this.chatId = chatId } + + /** Alias for calling [Builder.chatId] with `chatId.orElse(null)`. */ + fun chatId(chatId: Optional) = chatId(chatId.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 [BackgroundRemoveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): BackgroundRemoveParams = + BackgroundRemoveParams( + chatId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), + ) + } + + fun _body(): Optional> = + Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) + + fun _pathParam(index: Int): String = + when (index) { + 0 -> chatId ?: "" + 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 BackgroundRemoveParams && + chatId == other.chatId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(chatId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "BackgroundRemoveParams{chatId=$chatId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/batches/BatchListMessagesParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/BackgroundRetrieveParams.kt similarity index 77% rename from blooio-java-core/src/main/kotlin/com/blooio/api/models/batches/BatchListMessagesParams.kt rename to blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/BackgroundRetrieveParams.kt index 2ff3330..6604efb 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/models/batches/BatchListMessagesParams.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/BackgroundRetrieveParams.kt @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. -package com.blooio.api.models.batches +package com.blooio.api.models.chats.background import com.blooio.api.core.Params import com.blooio.api.core.http.Headers @@ -9,15 +9,18 @@ import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull -/** List messages in a batch (stub) */ -class BatchListMessagesParams +/** + * Get the current background image metadata for a conversation. Works for both 1-on-1 and group + * chats. + */ +class BackgroundRetrieveParams private constructor( - private val batchId: String?, + private val chatId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun batchId(): Optional = Optional.ofNullable(batchId) + fun chatId(): Optional = Optional.ofNullable(chatId) /** Additional headers to send with the request. */ fun _additionalHeaders(): Headers = additionalHeaders @@ -29,30 +32,30 @@ private constructor( companion object { - @JvmStatic fun none(): BatchListMessagesParams = builder().build() + @JvmStatic fun none(): BackgroundRetrieveParams = builder().build() - /** Returns a mutable builder for constructing an instance of [BatchListMessagesParams]. */ + /** Returns a mutable builder for constructing an instance of [BackgroundRetrieveParams]. */ @JvmStatic fun builder() = Builder() } - /** A builder for [BatchListMessagesParams]. */ + /** A builder for [BackgroundRetrieveParams]. */ class Builder internal constructor() { - private var batchId: String? = null + private var chatId: String? = null private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @JvmSynthetic - internal fun from(batchListMessagesParams: BatchListMessagesParams) = apply { - batchId = batchListMessagesParams.batchId - additionalHeaders = batchListMessagesParams.additionalHeaders.toBuilder() - additionalQueryParams = batchListMessagesParams.additionalQueryParams.toBuilder() + internal fun from(backgroundRetrieveParams: BackgroundRetrieveParams) = apply { + chatId = backgroundRetrieveParams.chatId + additionalHeaders = backgroundRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = backgroundRetrieveParams.additionalQueryParams.toBuilder() } - fun batchId(batchId: String?) = apply { this.batchId = batchId } + fun chatId(chatId: String?) = apply { this.chatId = chatId } - /** Alias for calling [Builder.batchId] with `batchId.orElse(null)`. */ - fun batchId(batchId: Optional) = batchId(batchId.getOrNull()) + /** Alias for calling [Builder.chatId] with `chatId.orElse(null)`. */ + fun chatId(chatId: Optional) = chatId(chatId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -153,13 +156,13 @@ private constructor( } /** - * Returns an immutable instance of [BatchListMessagesParams]. + * Returns an immutable instance of [BackgroundRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): BatchListMessagesParams = - BatchListMessagesParams( - batchId, + fun build(): BackgroundRetrieveParams = + BackgroundRetrieveParams( + chatId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -167,7 +170,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> batchId ?: "" + 0 -> chatId ?: "" else -> "" } @@ -180,14 +183,14 @@ private constructor( return true } - return other is BatchListMessagesParams && - batchId == other.batchId && + return other is BackgroundRetrieveParams && + chatId == other.chatId && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams } - override fun hashCode(): Int = Objects.hash(batchId, additionalHeaders, additionalQueryParams) + override fun hashCode(): Int = Objects.hash(chatId, additionalHeaders, additionalQueryParams) override fun toString() = - "BatchListMessagesParams{batchId=$batchId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "BackgroundRetrieveParams{chatId=$chatId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/BackgroundSetParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/BackgroundSetParams.kt new file mode 100644 index 0000000..39638a6 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/BackgroundSetParams.kt @@ -0,0 +1,460 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.background + +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.core.MultipartField +import com.blooio.api.core.Params +import com.blooio.api.core.checkRequired +import com.blooio.api.core.http.Headers +import com.blooio.api.core.http.QueryParams +import com.blooio.api.core.toImmutable +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonProperty +import java.io.InputStream +import java.nio.file.Path +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.io.path.inputStream +import kotlin.io.path.name +import kotlin.jvm.optionals.getOrNull + +/** + * Set or update the background image for a conversation. Works for both 1-on-1 and group chats. + * + * The uploaded image is converted into a PosterKit-compatible archive and applied to the iMessage + * conversation on the linked device. Supported formats: JPEG, PNG, GIF, WebP, HEIC/HEIF. Maximum + * file size: 10 MB. + */ +class BackgroundSetParams +private constructor( + private val chatId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun chatId(): Optional = Optional.ofNullable(chatId) + + /** + * The image file to set as the chat background + * + * @throws BlooioInvalidDataException 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 background(): InputStream = body.background() + + /** + * Returns the raw multipart value of [background]. + * + * Unlike [background], this method doesn't throw if the multipart field has an unexpected type. + */ + fun _background(): MultipartField = body._background() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + /** 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 [BackgroundSetParams]. + * + * The following fields are required: + * ```java + * .background() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BackgroundSetParams]. */ + class Builder internal constructor() { + + private var chatId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(backgroundSetParams: BackgroundSetParams) = apply { + chatId = backgroundSetParams.chatId + body = backgroundSetParams.body.toBuilder() + additionalHeaders = backgroundSetParams.additionalHeaders.toBuilder() + additionalQueryParams = backgroundSetParams.additionalQueryParams.toBuilder() + } + + fun chatId(chatId: String?) = apply { this.chatId = chatId } + + /** Alias for calling [Builder.chatId] with `chatId.orElse(null)`. */ + fun chatId(chatId: Optional) = chatId(chatId.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [background] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** The image file to set as the chat background */ + fun background(background: InputStream) = apply { body.background(background) } + + /** + * Sets [Builder.background] to an arbitrary multipart value. + * + * You should usually call [Builder.background] with a well-typed [InputStream] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun background(background: MultipartField) = apply { + body.background(background) + } + + /** The image file to set as the chat background */ + fun background(background: ByteArray) = apply { body.background(background) } + + /** The image file to set as the chat background */ + fun background(path: Path) = apply { body.background(path) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + 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 [BackgroundSetParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .background() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): BackgroundSetParams = + BackgroundSetParams( + chatId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Map> = + (mapOf("background" to _background()) + + _additionalBodyProperties().mapValues { (_, value) -> MultipartField.of(value) }) + .toImmutable() + + fun _pathParam(index: Int): String = + when (index) { + 0 -> chatId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + private constructor( + private val background: MultipartField, + private val additionalProperties: MutableMap, + ) { + + /** + * The image file to set as the chat background + * + * @throws BlooioInvalidDataException 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 background(): InputStream = background.value.getRequired("background") + + /** + * Returns the raw multipart value of [background]. + * + * Unlike [background], this method doesn't throw if the multipart field has an unexpected + * type. + */ + @JsonProperty("background") + @ExcludeMissing + fun _background(): MultipartField = background + + @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 [Body]. + * + * The following fields are required: + * ```java + * .background() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var background: MultipartField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + background = body.background + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** The image file to set as the chat background */ + fun background(background: InputStream) = background(MultipartField.of(background)) + + /** + * Sets [Builder.background] to an arbitrary multipart value. + * + * You should usually call [Builder.background] with a well-typed [InputStream] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun background(background: MultipartField) = apply { + this.background = background + } + + /** The image file to set as the chat background */ + fun background(background: ByteArray) = background(background.inputStream()) + + /** The image file to set as the chat background */ + fun background(path: Path) = + background( + MultipartField.builder() + .value(path.inputStream()) + .filename(path.name) + .build() + ) + + 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 [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .background() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body(checkRequired("background", background), additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + background() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + false + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + background == other.background && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(background, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{background=$background, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BackgroundSetParams && + chatId == other.chatId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(chatId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "BackgroundSetParams{chatId=$chatId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/ChatBackgroundResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/ChatBackgroundResponse.kt new file mode 100644 index 0000000..262582e --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/background/ChatBackgroundResponse.kt @@ -0,0 +1,346 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.background + +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Response for chat background operations */ +class ChatBackgroundResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val backgroundId: JsonField, + private val backgroundVersion: JsonField, + private val changed: JsonField, + private val chatId: JsonField, + private val hasBackground: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("background_id") + @ExcludeMissing + backgroundId: JsonField = JsonMissing.of(), + @JsonProperty("background_version") + @ExcludeMissing + backgroundVersion: JsonField = JsonMissing.of(), + @JsonProperty("changed") @ExcludeMissing changed: JsonField = JsonMissing.of(), + @JsonProperty("chat_id") @ExcludeMissing chatId: JsonField = JsonMissing.of(), + @JsonProperty("has_background") + @ExcludeMissing + hasBackground: JsonField = JsonMissing.of(), + ) : this(backgroundId, backgroundVersion, changed, chatId, hasBackground, mutableMapOf()) + + /** + * Unique identifier for the current background, or null if none + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun backgroundId(): Optional = backgroundId.getOptional("background_id") + + /** + * Version number of the background (for cache invalidation) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun backgroundVersion(): Optional = backgroundVersion.getOptional("background_version") + + /** + * Whether the background was changed by this operation (only present on PUT) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun changed(): Optional = changed.getOptional("changed") + + /** + * Normalized chat identifier (phone number, email, or group ID) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun chatId(): Optional = chatId.getOptional("chat_id") + + /** + * Whether the chat currently has a background set + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun hasBackground(): Optional = hasBackground.getOptional("has_background") + + /** + * Returns the raw JSON value of [backgroundId]. + * + * Unlike [backgroundId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("background_id") + @ExcludeMissing + fun _backgroundId(): JsonField = backgroundId + + /** + * Returns the raw JSON value of [backgroundVersion]. + * + * Unlike [backgroundVersion], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("background_version") + @ExcludeMissing + fun _backgroundVersion(): JsonField = backgroundVersion + + /** + * Returns the raw JSON value of [changed]. + * + * Unlike [changed], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("changed") @ExcludeMissing fun _changed(): JsonField = changed + + /** + * Returns the raw JSON value of [chatId]. + * + * Unlike [chatId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("chat_id") @ExcludeMissing fun _chatId(): JsonField = chatId + + /** + * Returns the raw JSON value of [hasBackground]. + * + * Unlike [hasBackground], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("has_background") + @ExcludeMissing + fun _hasBackground(): JsonField = hasBackground + + @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 [ChatBackgroundResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ChatBackgroundResponse]. */ + class Builder internal constructor() { + + private var backgroundId: JsonField = JsonMissing.of() + private var backgroundVersion: JsonField = JsonMissing.of() + private var changed: JsonField = JsonMissing.of() + private var chatId: JsonField = JsonMissing.of() + private var hasBackground: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(chatBackgroundResponse: ChatBackgroundResponse) = apply { + backgroundId = chatBackgroundResponse.backgroundId + backgroundVersion = chatBackgroundResponse.backgroundVersion + changed = chatBackgroundResponse.changed + chatId = chatBackgroundResponse.chatId + hasBackground = chatBackgroundResponse.hasBackground + additionalProperties = chatBackgroundResponse.additionalProperties.toMutableMap() + } + + /** Unique identifier for the current background, or null if none */ + fun backgroundId(backgroundId: String?) = backgroundId(JsonField.ofNullable(backgroundId)) + + /** Alias for calling [Builder.backgroundId] with `backgroundId.orElse(null)`. */ + fun backgroundId(backgroundId: Optional) = backgroundId(backgroundId.getOrNull()) + + /** + * Sets [Builder.backgroundId] to an arbitrary JSON value. + * + * You should usually call [Builder.backgroundId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun backgroundId(backgroundId: JsonField) = apply { + this.backgroundId = backgroundId + } + + /** Version number of the background (for cache invalidation) */ + fun backgroundVersion(backgroundVersion: Long?) = + backgroundVersion(JsonField.ofNullable(backgroundVersion)) + + /** + * Alias for [Builder.backgroundVersion]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun backgroundVersion(backgroundVersion: Long) = + backgroundVersion(backgroundVersion as Long?) + + /** Alias for calling [Builder.backgroundVersion] with `backgroundVersion.orElse(null)`. */ + fun backgroundVersion(backgroundVersion: Optional) = + backgroundVersion(backgroundVersion.getOrNull()) + + /** + * Sets [Builder.backgroundVersion] to an arbitrary JSON value. + * + * You should usually call [Builder.backgroundVersion] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun backgroundVersion(backgroundVersion: JsonField) = apply { + this.backgroundVersion = backgroundVersion + } + + /** Whether the background was changed by this operation (only present on PUT) */ + fun changed(changed: Boolean) = changed(JsonField.of(changed)) + + /** + * Sets [Builder.changed] to an arbitrary JSON value. + * + * You should usually call [Builder.changed] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun changed(changed: JsonField) = apply { this.changed = changed } + + /** Normalized chat identifier (phone number, email, or group ID) */ + fun chatId(chatId: String) = chatId(JsonField.of(chatId)) + + /** + * Sets [Builder.chatId] to an arbitrary JSON value. + * + * You should usually call [Builder.chatId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun chatId(chatId: JsonField) = apply { this.chatId = chatId } + + /** Whether the chat currently has a background set */ + fun hasBackground(hasBackground: Boolean) = hasBackground(JsonField.of(hasBackground)) + + /** + * Sets [Builder.hasBackground] to an arbitrary JSON value. + * + * You should usually call [Builder.hasBackground] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun hasBackground(hasBackground: JsonField) = apply { + this.hasBackground = hasBackground + } + + 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 [ChatBackgroundResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ChatBackgroundResponse = + ChatBackgroundResponse( + backgroundId, + backgroundVersion, + changed, + chatId, + hasBackground, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ChatBackgroundResponse = apply { + if (validated) { + return@apply + } + + backgroundId() + backgroundVersion() + changed() + chatId() + hasBackground() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (backgroundId.asKnown().isPresent) 1 else 0) + + (if (backgroundVersion.asKnown().isPresent) 1 else 0) + + (if (changed.asKnown().isPresent) 1 else 0) + + (if (chatId.asKnown().isPresent) 1 else 0) + + (if (hasBackground.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ChatBackgroundResponse && + backgroundId == other.backgroundId && + backgroundVersion == other.backgroundVersion && + changed == other.changed && + chatId == other.chatId && + hasBackground == other.hasBackground && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + backgroundId, + backgroundVersion, + changed, + chatId, + hasBackground, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ChatBackgroundResponse{backgroundId=$backgroundId, backgroundVersion=$backgroundVersion, changed=$changed, chatId=$chatId, hasBackground=$hasBackground, additionalProperties=$additionalProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/LinkPreview.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/LinkPreview.kt new file mode 100644 index 0000000..e3d3ebf --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/LinkPreview.kt @@ -0,0 +1,206 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.messages + +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional + +/** + * Rich-link-preview overrides for URL messages (iMessage URL balloon). All fields are optional. + * Only applies when the message text (or the concatenated part text) is exactly a single http(s) + * URL. If omitted but the text is a URL, Blooio auto-fetches the page's Open Graph metadata to + * generate a preview. If the image download fails, the send still succeeds — Blooio silently falls + * back to the auto-generated preview. + */ +class LinkPreview +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val imageUrl: JsonField, + private val title: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("image_url") @ExcludeMissing imageUrl: JsonField = JsonMissing.of(), + @JsonProperty("title") @ExcludeMissing title: JsonField = JsonMissing.of(), + ) : this(imageUrl, title, mutableMapOf()) + + /** + * HTTPS URL to an image (png, jpg, webp, gif). Blooio downloads the image server-side and + * attaches it as the rich-link hero. Max 16 MB. If the download fails or returns a non-image + * MIME, the send falls back to auto-fetched OG metadata. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun imageUrl(): Optional = imageUrl.getOptional("image_url") + + /** + * Bold title line rendered in the iMessage bubble. Overrides the page's ``. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun title(): Optional = title.getOptional("title") + + /** + * Returns the raw JSON value of [imageUrl]. + * + * Unlike [imageUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("image_url") @ExcludeMissing fun _imageUrl(): JsonField = imageUrl + + /** + * Returns the raw JSON value of [title]. + * + * Unlike [title], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("title") @ExcludeMissing fun _title(): JsonField = title + + @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 [LinkPreview]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [LinkPreview]. */ + class Builder internal constructor() { + + private var imageUrl: JsonField = JsonMissing.of() + private var title: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(linkPreview: LinkPreview) = apply { + imageUrl = linkPreview.imageUrl + title = linkPreview.title + additionalProperties = linkPreview.additionalProperties.toMutableMap() + } + + /** + * HTTPS URL to an image (png, jpg, webp, gif). Blooio downloads the image server-side and + * attaches it as the rich-link hero. Max 16 MB. If the download fails or returns a + * non-image MIME, the send falls back to auto-fetched OG metadata. + */ + fun imageUrl(imageUrl: String) = imageUrl(JsonField.of(imageUrl)) + + /** + * Sets [Builder.imageUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.imageUrl] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun imageUrl(imageUrl: JsonField) = apply { this.imageUrl = imageUrl } + + /** + * Bold title line rendered in the iMessage bubble. Overrides the page's ``. + */ + fun title(title: String) = title(JsonField.of(title)) + + /** + * Sets [Builder.title] to an arbitrary JSON value. + * + * You should usually call [Builder.title] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun title(title: JsonField) = apply { this.title = title } + + 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 [LinkPreview]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): LinkPreview = LinkPreview(imageUrl, title, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): LinkPreview = apply { + if (validated) { + return@apply + } + + imageUrl() + title() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (imageUrl.asKnown().isPresent) 1 else 0) + (if (title.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is LinkPreview && + imageUrl == other.imageUrl && + title == other.title && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(imageUrl, title, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "LinkPreview{imageUrl=$imageUrl, title=$title, additionalProperties=$additionalProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageGetStatusParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageGetStatusParams.kt similarity index 84% rename from blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageGetStatusParams.kt rename to blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageGetStatusParams.kt index bf14e64..0e18b4c 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageGetStatusParams.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageGetStatusParams.kt @@ -1,22 +1,26 @@ // File generated from our OpenAPI spec by Stainless. -package com.blooio.api.models.messages +package com.blooio.api.models.chats.messages import com.blooio.api.core.Params +import com.blooio.api.core.checkRequired import com.blooio.api.core.http.Headers import com.blooio.api.core.http.QueryParams import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull -/** Get current delivery status only */ +/** Get delivery status for a specific message. */ class MessageGetStatusParams private constructor( + private val chatId: String, private val messageId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { + fun chatId(): String = chatId + fun messageId(): Optional = Optional.ofNullable(messageId) /** Additional headers to send with the request. */ @@ -29,26 +33,35 @@ private constructor( companion object { - @JvmStatic fun none(): MessageGetStatusParams = builder().build() - - /** Returns a mutable builder for constructing an instance of [MessageGetStatusParams]. */ + /** + * Returns a mutable builder for constructing an instance of [MessageGetStatusParams]. + * + * The following fields are required: + * ```java + * .chatId() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [MessageGetStatusParams]. */ class Builder internal constructor() { + private var chatId: String? = null private var messageId: String? = null private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @JvmSynthetic internal fun from(messageGetStatusParams: MessageGetStatusParams) = apply { + chatId = messageGetStatusParams.chatId messageId = messageGetStatusParams.messageId additionalHeaders = messageGetStatusParams.additionalHeaders.toBuilder() additionalQueryParams = messageGetStatusParams.additionalQueryParams.toBuilder() } + fun chatId(chatId: String) = apply { this.chatId = chatId } + fun messageId(messageId: String?) = apply { this.messageId = messageId } /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ @@ -156,9 +169,17 @@ private constructor( * Returns an immutable instance of [MessageGetStatusParams]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .chatId() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): MessageGetStatusParams = MessageGetStatusParams( + checkRequired("chatId", chatId), messageId, additionalHeaders.build(), additionalQueryParams.build(), @@ -167,7 +188,8 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> messageId ?: "" + 0 -> chatId + 1 -> messageId ?: "" else -> "" } @@ -181,13 +203,15 @@ private constructor( } return other is MessageGetStatusParams && + chatId == other.chatId && messageId == other.messageId && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams } - override fun hashCode(): Int = Objects.hash(messageId, additionalHeaders, additionalQueryParams) + override fun hashCode(): Int = + Objects.hash(chatId, messageId, additionalHeaders, additionalQueryParams) override fun toString() = - "MessageGetStatusParams{messageId=$messageId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "MessageGetStatusParams{chatId=$chatId, messageId=$messageId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageRetrieveResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageGetStatusResponse.kt similarity index 65% rename from blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageRetrieveResponse.kt rename to blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageGetStatusResponse.kt index 59a17ee..6aaf8b0 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageRetrieveResponse.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageGetStatusResponse.kt @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. -package com.blooio.api.models.messages +package com.blooio.api.models.chats.messages import com.blooio.api.core.Enum import com.blooio.api.core.ExcludeMissing @@ -17,50 +17,42 @@ import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull -class MessageRetrieveResponse +class MessageGetStatusResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val apiKey: JsonField, - private val attachmentsCount: JsonField, + private val chatId: JsonField, private val direction: JsonField, - private val externalId: JsonField, + private val error: JsonField, private val messageId: JsonField, - private val metadata: JsonValue, - private val protocol: JsonField, + private val protocol: JsonField, private val status: JsonField, - private val textLength: JsonField, + private val timeDelivered: JsonField, private val timeSent: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("api_key") @ExcludeMissing apiKey: JsonField = JsonMissing.of(), - @JsonProperty("attachments_count") - @ExcludeMissing - attachmentsCount: JsonField = JsonMissing.of(), + @JsonProperty("chat_id") @ExcludeMissing chatId: JsonField = JsonMissing.of(), @JsonProperty("direction") @ExcludeMissing direction: JsonField = JsonMissing.of(), - @JsonProperty("external_id") - @ExcludeMissing - externalId: JsonField = JsonMissing.of(), + @JsonProperty("error") @ExcludeMissing error: JsonField = JsonMissing.of(), @JsonProperty("message_id") @ExcludeMissing messageId: JsonField = JsonMissing.of(), - @JsonProperty("metadata") @ExcludeMissing metadata: JsonValue = JsonMissing.of(), - @JsonProperty("protocol") @ExcludeMissing protocol: JsonField = JsonMissing.of(), + @JsonProperty("protocol") @ExcludeMissing protocol: JsonField = JsonMissing.of(), @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), - @JsonProperty("text_length") @ExcludeMissing textLength: JsonField = JsonMissing.of(), + @JsonProperty("time_delivered") + @ExcludeMissing + timeDelivered: JsonField = JsonMissing.of(), @JsonProperty("time_sent") @ExcludeMissing timeSent: JsonField = JsonMissing.of(), ) : this( - apiKey, - attachmentsCount, + chatId, direction, - externalId, + error, messageId, - metadata, protocol, status, - textLength, + timeDelivered, timeSent, mutableMapOf(), ) @@ -69,13 +61,7 @@ private constructor( * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun apiKey(): Optional = apiKey.getOptional("api_key") - - /** - * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun attachmentsCount(): Optional = attachmentsCount.getOptional("attachments_count") + fun chatId(): Optional = chatId.getOptional("chat_id") /** * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the @@ -84,12 +70,10 @@ private constructor( fun direction(): Optional = direction.getOptional("direction") /** - * Recipient phone number. - * * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun externalId(): Optional = externalId.getOptional("external_id") + fun error(): Optional = error.getOptional("error") /** * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the @@ -98,26 +82,12 @@ private constructor( fun messageId(): Optional = messageId.getOptional("message_id") /** - * Original metadata provided plus system generated fields. - * - * This arbitrary value can be deserialized into a custom type using the `convert` method: - * ```java - * MyClass myObject = messageRetrieveResponse.metadata().convert(MyClass.class); - * ``` - */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonValue = metadata - - /** - * The protocol used to send the message (e.g., imessage, rcs, sms). - * * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun protocol(): Optional = protocol.getOptional("protocol") + fun protocol(): Optional = protocol.getOptional("protocol") /** - * Current delivery status. - * * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ @@ -127,32 +97,20 @@ private constructor( * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun textLength(): Optional = textLength.getOptional("text_length") + fun timeDelivered(): Optional = timeDelivered.getOptional("time_delivered") /** - * Unix timestamp (ms) when the message was queued/sent. - * * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun timeSent(): Optional = timeSent.getOptional("time_sent") /** - * Returns the raw JSON value of [apiKey]. + * Returns the raw JSON value of [chatId]. * - * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [chatId], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("api_key") @ExcludeMissing fun _apiKey(): JsonField = apiKey - - /** - * Returns the raw JSON value of [attachmentsCount]. - * - * Unlike [attachmentsCount], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("attachments_count") - @ExcludeMissing - fun _attachmentsCount(): JsonField = attachmentsCount + @JsonProperty("chat_id") @ExcludeMissing fun _chatId(): JsonField = chatId /** * Returns the raw JSON value of [direction]. @@ -162,11 +120,11 @@ private constructor( @JsonProperty("direction") @ExcludeMissing fun _direction(): JsonField = direction /** - * Returns the raw JSON value of [externalId]. + * Returns the raw JSON value of [error]. * - * Unlike [externalId], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [error], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("external_id") @ExcludeMissing fun _externalId(): JsonField = externalId + @JsonProperty("error") @ExcludeMissing fun _error(): JsonField = error /** * Returns the raw JSON value of [messageId]. @@ -180,7 +138,7 @@ private constructor( * * Unlike [protocol], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("protocol") @ExcludeMissing fun _protocol(): JsonField = protocol + @JsonProperty("protocol") @ExcludeMissing fun _protocol(): JsonField = protocol /** * Returns the raw JSON value of [status]. @@ -190,11 +148,13 @@ private constructor( @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status /** - * Returns the raw JSON value of [textLength]. + * Returns the raw JSON value of [timeDelivered]. * - * Unlike [textLength], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [timeDelivered], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("text_length") @ExcludeMissing fun _textLength(): JsonField = textLength + @JsonProperty("time_delivered") + @ExcludeMissing + fun _timeDelivered(): JsonField = timeDelivered /** * Returns the raw JSON value of [timeSent]. @@ -217,63 +177,45 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [MessageRetrieveResponse]. */ + /** Returns a mutable builder for constructing an instance of [MessageGetStatusResponse]. */ @JvmStatic fun builder() = Builder() } - /** A builder for [MessageRetrieveResponse]. */ + /** A builder for [MessageGetStatusResponse]. */ class Builder internal constructor() { - private var apiKey: JsonField = JsonMissing.of() - private var attachmentsCount: JsonField = JsonMissing.of() + private var chatId: JsonField = JsonMissing.of() private var direction: JsonField = JsonMissing.of() - private var externalId: JsonField = JsonMissing.of() + private var error: JsonField = JsonMissing.of() private var messageId: JsonField = JsonMissing.of() - private var metadata: JsonValue = JsonMissing.of() - private var protocol: JsonField = JsonMissing.of() + private var protocol: JsonField = JsonMissing.of() private var status: JsonField = JsonMissing.of() - private var textLength: JsonField = JsonMissing.of() + private var timeDelivered: JsonField = JsonMissing.of() private var timeSent: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(messageRetrieveResponse: MessageRetrieveResponse) = apply { - apiKey = messageRetrieveResponse.apiKey - attachmentsCount = messageRetrieveResponse.attachmentsCount - direction = messageRetrieveResponse.direction - externalId = messageRetrieveResponse.externalId - messageId = messageRetrieveResponse.messageId - metadata = messageRetrieveResponse.metadata - protocol = messageRetrieveResponse.protocol - status = messageRetrieveResponse.status - textLength = messageRetrieveResponse.textLength - timeSent = messageRetrieveResponse.timeSent - additionalProperties = messageRetrieveResponse.additionalProperties.toMutableMap() + internal fun from(messageGetStatusResponse: MessageGetStatusResponse) = apply { + chatId = messageGetStatusResponse.chatId + direction = messageGetStatusResponse.direction + error = messageGetStatusResponse.error + messageId = messageGetStatusResponse.messageId + protocol = messageGetStatusResponse.protocol + status = messageGetStatusResponse.status + timeDelivered = messageGetStatusResponse.timeDelivered + timeSent = messageGetStatusResponse.timeSent + additionalProperties = messageGetStatusResponse.additionalProperties.toMutableMap() } - fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) + fun chatId(chatId: String) = chatId(JsonField.of(chatId)) /** - * Sets [Builder.apiKey] to an arbitrary JSON value. + * Sets [Builder.chatId] to an arbitrary JSON value. * - * You should usually call [Builder.apiKey] with a well-typed [String] value instead. This + * You should usually call [Builder.chatId] with a well-typed [String] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } - - fun attachmentsCount(attachmentsCount: Long) = - attachmentsCount(JsonField.of(attachmentsCount)) - - /** - * Sets [Builder.attachmentsCount] to an arbitrary JSON value. - * - * You should usually call [Builder.attachmentsCount] with a well-typed [Long] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun attachmentsCount(attachmentsCount: JsonField) = apply { - this.attachmentsCount = attachmentsCount - } + fun chatId(chatId: JsonField) = apply { this.chatId = chatId } fun direction(direction: Direction) = direction(JsonField.of(direction)) @@ -286,17 +228,18 @@ private constructor( */ fun direction(direction: JsonField) = apply { this.direction = direction } - /** Recipient phone number. */ - fun externalId(externalId: String) = externalId(JsonField.of(externalId)) + fun error(error: String?) = error(JsonField.ofNullable(error)) + + /** Alias for calling [Builder.error] with `error.orElse(null)`. */ + fun error(error: Optional) = error(error.getOrNull()) /** - * Sets [Builder.externalId] to an arbitrary JSON value. + * Sets [Builder.error] to an arbitrary JSON value. * - * You should usually call [Builder.externalId] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. + * You should usually call [Builder.error] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun externalId(externalId: JsonField) = apply { this.externalId = externalId } + fun error(error: JsonField) = apply { this.error = error } fun messageId(messageId: String) = messageId(JsonField.of(messageId)) @@ -309,22 +252,24 @@ private constructor( */ fun messageId(messageId: JsonField) = apply { this.messageId = messageId } - /** Original metadata provided plus system generated fields. */ - fun metadata(metadata: JsonValue) = apply { this.metadata = metadata } + fun protocol(protocol: Protocol?) = protocol(JsonField.ofNullable(protocol)) - /** The protocol used to send the message (e.g., imessage, rcs, sms). */ - fun protocol(protocol: String) = protocol(JsonField.of(protocol)) + /** Alias for calling [Builder.protocol] with `protocol.orElse(null)`. */ + fun protocol(protocol: Optional) = protocol(protocol.getOrNull()) /** * Sets [Builder.protocol] to an arbitrary JSON value. * - * You should usually call [Builder.protocol] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. + * You should usually call [Builder.protocol] with a well-typed [Protocol] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun protocol(protocol: JsonField) = apply { this.protocol = protocol } + fun protocol(protocol: JsonField) = apply { this.protocol = protocol } + + fun status(status: Status?) = status(JsonField.ofNullable(status)) - /** Current delivery status. */ - fun status(status: Status) = status(JsonField.of(status)) + /** Alias for calling [Builder.status] with `status.orElse(null)`. */ + fun status(status: Optional) = status(status.getOrNull()) /** * Sets [Builder.status] to an arbitrary JSON value. @@ -334,17 +279,29 @@ private constructor( */ fun status(status: JsonField) = apply { this.status = status } - fun textLength(textLength: Long) = textLength(JsonField.of(textLength)) + fun timeDelivered(timeDelivered: Long?) = timeDelivered(JsonField.ofNullable(timeDelivered)) /** - * Sets [Builder.textLength] to an arbitrary JSON value. + * Alias for [Builder.timeDelivered]. * - * You should usually call [Builder.textLength] with a well-typed [Long] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. + * This unboxed primitive overload exists for backwards compatibility. */ - fun textLength(textLength: JsonField) = apply { this.textLength = textLength } + fun timeDelivered(timeDelivered: Long) = timeDelivered(timeDelivered as Long?) + + /** Alias for calling [Builder.timeDelivered] with `timeDelivered.orElse(null)`. */ + fun timeDelivered(timeDelivered: Optional) = timeDelivered(timeDelivered.getOrNull()) + + /** + * Sets [Builder.timeDelivered] to an arbitrary JSON value. + * + * You should usually call [Builder.timeDelivered] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun timeDelivered(timeDelivered: JsonField) = apply { + this.timeDelivered = timeDelivered + } - /** Unix timestamp (ms) when the message was queued/sent. */ fun timeSent(timeSent: Long) = timeSent(JsonField.of(timeSent)) /** @@ -375,21 +332,19 @@ private constructor( } /** - * Returns an immutable instance of [MessageRetrieveResponse]. + * Returns an immutable instance of [MessageGetStatusResponse]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): MessageRetrieveResponse = - MessageRetrieveResponse( - apiKey, - attachmentsCount, + fun build(): MessageGetStatusResponse = + MessageGetStatusResponse( + chatId, direction, - externalId, + error, messageId, - metadata, protocol, status, - textLength, + timeDelivered, timeSent, additionalProperties.toMutableMap(), ) @@ -397,19 +352,18 @@ private constructor( private var validated: Boolean = false - fun validate(): MessageRetrieveResponse = apply { + fun validate(): MessageGetStatusResponse = apply { if (validated) { return@apply } - apiKey() - attachmentsCount() + chatId() direction().ifPresent { it.validate() } - externalId() + error() messageId() - protocol() + protocol().ifPresent { it.validate() } status().ifPresent { it.validate() } - textLength() + timeDelivered() timeSent() validated = true } @@ -429,14 +383,13 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (apiKey.asKnown().isPresent) 1 else 0) + - (if (attachmentsCount.asKnown().isPresent) 1 else 0) + + (if (chatId.asKnown().isPresent) 1 else 0) + (direction.asKnown().getOrNull()?.validity() ?: 0) + - (if (externalId.asKnown().isPresent) 1 else 0) + + (if (error.asKnown().isPresent) 1 else 0) + (if (messageId.asKnown().isPresent) 1 else 0) + - (if (protocol.asKnown().isPresent) 1 else 0) + + (protocol.asKnown().getOrNull()?.validity() ?: 0) + (status.asKnown().getOrNull()?.validity() ?: 0) + - (if (textLength.asKnown().isPresent) 1 else 0) + + (if (timeDelivered.asKnown().isPresent) 1 else 0) + (if (timeSent.asKnown().isPresent) 1 else 0) class Direction @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -453,17 +406,17 @@ private constructor( companion object { - @JvmField val OUTBOUND = of("outbound") - @JvmField val INBOUND = of("inbound") + @JvmField val OUTBOUND = of("outbound") + @JvmStatic fun of(value: String) = Direction(JsonField.of(value)) } /** An enum containing [Direction]'s known values. */ enum class Known { - OUTBOUND, INBOUND, + OUTBOUND, } /** @@ -476,8 +429,8 @@ private constructor( * - It was constructed with an arbitrary value using the [of] method. */ enum class Value { - OUTBOUND, INBOUND, + OUTBOUND, /** * An enum member indicating that [Direction] was instantiated with an unknown value. */ @@ -493,8 +446,8 @@ private constructor( */ fun value(): Value = when (this) { - OUTBOUND -> Value.OUTBOUND INBOUND -> Value.INBOUND + OUTBOUND -> Value.OUTBOUND else -> Value._UNKNOWN } @@ -509,8 +462,8 @@ private constructor( */ fun known(): Known = when (this) { - OUTBOUND -> Known.OUTBOUND INBOUND -> Known.INBOUND + OUTBOUND -> Known.OUTBOUND else -> throw BlooioInvalidDataException("Unknown Direction: $value") } @@ -566,7 +519,143 @@ private constructor( override fun toString() = value.toString() } - /** Current delivery status. */ + class Protocol @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val IMESSAGE = of("imessage") + + @JvmField val SMS = of("sms") + + @JvmField val RCS = of("rcs") + + @JvmField val NON_IMESSAGE = of("non-imessage") + + @JvmStatic fun of(value: String) = Protocol(JsonField.of(value)) + } + + /** An enum containing [Protocol]'s known values. */ + enum class Known { + IMESSAGE, + SMS, + RCS, + NON_IMESSAGE, + } + + /** + * An enum containing [Protocol]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Protocol] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + IMESSAGE, + SMS, + RCS, + NON_IMESSAGE, + /** An enum member indicating that [Protocol] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + IMESSAGE -> Value.IMESSAGE + SMS -> Value.SMS + RCS -> Value.RCS + NON_IMESSAGE -> Value.NON_IMESSAGE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + IMESSAGE -> Known.IMESSAGE + SMS -> Known.SMS + RCS -> Known.RCS + NON_IMESSAGE -> Known.NON_IMESSAGE + else -> throw BlooioInvalidDataException("Unknown Protocol: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Protocol = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Protocol && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { /** @@ -591,10 +680,10 @@ private constructor( @JvmField val FAILED = of("failed") - @JvmField val CANCELLED = of("cancelled") - @JvmField val CANCELLATION_REQUESTED = of("cancellation_requested") + @JvmField val CANCELLED = of("cancelled") + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) } @@ -605,8 +694,8 @@ private constructor( SENT, DELIVERED, FAILED, - CANCELLED, CANCELLATION_REQUESTED, + CANCELLED, } /** @@ -624,8 +713,8 @@ private constructor( SENT, DELIVERED, FAILED, - CANCELLED, CANCELLATION_REQUESTED, + CANCELLED, /** An enum member indicating that [Status] was instantiated with an unknown value. */ _UNKNOWN, } @@ -644,8 +733,8 @@ private constructor( SENT -> Value.SENT DELIVERED -> Value.DELIVERED FAILED -> Value.FAILED - CANCELLED -> Value.CANCELLED CANCELLATION_REQUESTED -> Value.CANCELLATION_REQUESTED + CANCELLED -> Value.CANCELLED else -> Value._UNKNOWN } @@ -665,8 +754,8 @@ private constructor( SENT -> Known.SENT DELIVERED -> Known.DELIVERED FAILED -> Known.FAILED - CANCELLED -> Known.CANCELLED CANCELLATION_REQUESTED -> Known.CANCELLATION_REQUESTED + CANCELLED -> Known.CANCELLED else -> throw BlooioInvalidDataException("Unknown Status: $value") } @@ -727,31 +816,27 @@ private constructor( return true } - return other is MessageRetrieveResponse && - apiKey == other.apiKey && - attachmentsCount == other.attachmentsCount && + return other is MessageGetStatusResponse && + chatId == other.chatId && direction == other.direction && - externalId == other.externalId && + error == other.error && messageId == other.messageId && - metadata == other.metadata && protocol == other.protocol && status == other.status && - textLength == other.textLength && + timeDelivered == other.timeDelivered && timeSent == other.timeSent && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { Objects.hash( - apiKey, - attachmentsCount, + chatId, direction, - externalId, + error, messageId, - metadata, protocol, status, - textLength, + timeDelivered, timeSent, additionalProperties, ) @@ -760,5 +845,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "MessageRetrieveResponse{apiKey=$apiKey, attachmentsCount=$attachmentsCount, direction=$direction, externalId=$externalId, messageId=$messageId, metadata=$metadata, protocol=$protocol, status=$status, textLength=$textLength, timeSent=$timeSent, additionalProperties=$additionalProperties}" + "MessageGetStatusResponse{chatId=$chatId, direction=$direction, error=$error, messageId=$messageId, protocol=$protocol, status=$status, timeDelivered=$timeDelivered, timeSent=$timeSent, additionalProperties=$additionalProperties}" } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageListParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageListParams.kt new file mode 100644 index 0000000..6761c61 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageListParams.kt @@ -0,0 +1,585 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.messages + +import com.blooio.api.core.Enum +import com.blooio.api.core.JsonField +import com.blooio.api.core.Params +import com.blooio.api.core.http.Headers +import com.blooio.api.core.http.QueryParams +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonCreator +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** List all messages in a conversation with optional filtering. */ +class MessageListParams +private constructor( + private val chatId: String?, + private val direction: Direction?, + private val limit: Long?, + private val offset: Long?, + private val since: Long?, + private val sort: Sort?, + private val until: Long?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun chatId(): Optional = Optional.ofNullable(chatId) + + /** Filter by message direction */ + fun direction(): Optional = Optional.ofNullable(direction) + + /** Maximum number of items to return (1-200) */ + fun limit(): Optional = Optional.ofNullable(limit) + + /** Number of items to skip */ + fun offset(): Optional = Optional.ofNullable(offset) + + /** Only messages sent after this timestamp (ms) */ + fun since(): Optional = Optional.ofNullable(since) + + /** Sort order by time */ + fun sort(): Optional = Optional.ofNullable(sort) + + /** Only messages sent before this timestamp (ms) */ + fun until(): Optional = Optional.ofNullable(until) + + /** 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(): MessageListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [MessageListParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [MessageListParams]. */ + class Builder internal constructor() { + + private var chatId: String? = null + private var direction: Direction? = null + private var limit: Long? = null + private var offset: Long? = null + private var since: Long? = null + private var sort: Sort? = null + private var until: Long? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(messageListParams: MessageListParams) = apply { + chatId = messageListParams.chatId + direction = messageListParams.direction + limit = messageListParams.limit + offset = messageListParams.offset + since = messageListParams.since + sort = messageListParams.sort + until = messageListParams.until + additionalHeaders = messageListParams.additionalHeaders.toBuilder() + additionalQueryParams = messageListParams.additionalQueryParams.toBuilder() + } + + fun chatId(chatId: String?) = apply { this.chatId = chatId } + + /** Alias for calling [Builder.chatId] with `chatId.orElse(null)`. */ + fun chatId(chatId: Optional) = chatId(chatId.getOrNull()) + + /** Filter by message direction */ + fun direction(direction: Direction?) = apply { this.direction = direction } + + /** Alias for calling [Builder.direction] with `direction.orElse(null)`. */ + fun direction(direction: Optional) = direction(direction.getOrNull()) + + /** Maximum number of items to return (1-200) */ + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) + + /** Alias for calling [Builder.limit] with `limit.orElse(null)`. */ + fun limit(limit: Optional) = limit(limit.getOrNull()) + + /** Number of items to skip */ + fun offset(offset: Long?) = apply { this.offset = offset } + + /** + * Alias for [Builder.offset]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun offset(offset: Long) = offset(offset as Long?) + + /** Alias for calling [Builder.offset] with `offset.orElse(null)`. */ + fun offset(offset: Optional) = offset(offset.getOrNull()) + + /** Only messages sent after this timestamp (ms) */ + fun since(since: Long?) = apply { this.since = since } + + /** + * Alias for [Builder.since]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun since(since: Long) = since(since as Long?) + + /** Alias for calling [Builder.since] with `since.orElse(null)`. */ + fun since(since: Optional) = since(since.getOrNull()) + + /** Sort order by time */ + fun sort(sort: Sort?) = apply { this.sort = sort } + + /** Alias for calling [Builder.sort] with `sort.orElse(null)`. */ + fun sort(sort: Optional) = sort(sort.getOrNull()) + + /** Only messages sent before this timestamp (ms) */ + fun until(until: Long?) = apply { this.until = until } + + /** + * Alias for [Builder.until]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun until(until: Long) = until(until as Long?) + + /** Alias for calling [Builder.until] with `until.orElse(null)`. */ + fun until(until: Optional) = until(until.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) + } + + /** + * Returns an immutable instance of [MessageListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): MessageListParams = + MessageListParams( + chatId, + direction, + limit, + offset, + since, + sort, + until, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> chatId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + direction?.let { put("direction", it.toString()) } + limit?.let { put("limit", it.toString()) } + offset?.let { put("offset", it.toString()) } + since?.let { put("since", it.toString()) } + sort?.let { put("sort", it.toString()) } + until?.let { put("until", it.toString()) } + putAll(additionalQueryParams) + } + .build() + + /** Filter by message direction */ + class Direction @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val INBOUND = of("inbound") + + @JvmField val OUTBOUND = of("outbound") + + @JvmStatic fun of(value: String) = Direction(JsonField.of(value)) + } + + /** An enum containing [Direction]'s known values. */ + enum class Known { + INBOUND, + OUTBOUND, + } + + /** + * An enum containing [Direction]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Direction] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + INBOUND, + OUTBOUND, + /** + * An enum member indicating that [Direction] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + INBOUND -> Value.INBOUND + OUTBOUND -> Value.OUTBOUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + INBOUND -> Known.INBOUND + OUTBOUND -> Known.OUTBOUND + else -> throw BlooioInvalidDataException("Unknown Direction: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Direction = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Direction && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Sort order by time */ + class Sort @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val ASC = of("asc") + + @JvmField val DESC = of("desc") + + @JvmStatic fun of(value: String) = Sort(JsonField.of(value)) + } + + /** An enum containing [Sort]'s known values. */ + enum class Known { + ASC, + DESC, + } + + /** + * An enum containing [Sort]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Sort] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + ASC, + DESC, + /** An enum member indicating that [Sort] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + ASC -> Value.ASC + DESC -> Value.DESC + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + ASC -> Known.ASC + DESC -> Known.DESC + else -> throw BlooioInvalidDataException("Unknown Sort: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Sort = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Sort && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is MessageListParams && + chatId == other.chatId && + direction == other.direction && + limit == other.limit && + offset == other.offset && + since == other.since && + sort == other.sort && + until == other.until && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + chatId, + direction, + limit, + offset, + since, + sort, + until, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "MessageListParams{chatId=$chatId, direction=$direction, limit=$limit, offset=$offset, since=$since, sort=$sort, until=$until, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageListResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageListResponse.kt new file mode 100644 index 0000000..819c4b0 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageListResponse.kt @@ -0,0 +1,1346 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.messages + +import com.blooio.api.core.Enum +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.core.checkKnown +import com.blooio.api.core.toImmutable +import com.blooio.api.errors.BlooioInvalidDataException +import com.blooio.api.models.contacts.Pagination +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class MessageListResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val chatId: JsonField, + private val messages: JsonField>, + private val pagination: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("chat_id") @ExcludeMissing chatId: JsonField = JsonMissing.of(), + @JsonProperty("messages") + @ExcludeMissing + messages: JsonField> = JsonMissing.of(), + @JsonProperty("pagination") + @ExcludeMissing + pagination: JsonField = JsonMissing.of(), + ) : this(chatId, messages, pagination, mutableMapOf()) + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun chatId(): Optional = chatId.getOptional("chat_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun messages(): Optional> = messages.getOptional("messages") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun pagination(): Optional = pagination.getOptional("pagination") + + /** + * Returns the raw JSON value of [chatId]. + * + * Unlike [chatId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("chat_id") @ExcludeMissing fun _chatId(): JsonField = chatId + + /** + * Returns the raw JSON value of [messages]. + * + * Unlike [messages], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("messages") @ExcludeMissing fun _messages(): JsonField> = messages + + /** + * Returns the raw JSON value of [pagination]. + * + * Unlike [pagination], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pagination") + @ExcludeMissing + fun _pagination(): JsonField = pagination + + @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 [MessageListResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [MessageListResponse]. */ + class Builder internal constructor() { + + private var chatId: JsonField = JsonMissing.of() + private var messages: JsonField>? = null + private var pagination: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(messageListResponse: MessageListResponse) = apply { + chatId = messageListResponse.chatId + messages = messageListResponse.messages.map { it.toMutableList() } + pagination = messageListResponse.pagination + additionalProperties = messageListResponse.additionalProperties.toMutableMap() + } + + fun chatId(chatId: String) = chatId(JsonField.of(chatId)) + + /** + * Sets [Builder.chatId] to an arbitrary JSON value. + * + * You should usually call [Builder.chatId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun chatId(chatId: JsonField) = apply { this.chatId = chatId } + + fun messages(messages: List) = messages(JsonField.of(messages)) + + /** + * Sets [Builder.messages] to an arbitrary JSON value. + * + * You should usually call [Builder.messages] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun messages(messages: JsonField>) = apply { + this.messages = messages.map { it.toMutableList() } + } + + /** + * Adds a single [Message] to [messages]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMessage(message: Message) = apply { + messages = + (messages ?: JsonField.of(mutableListOf())).also { + checkKnown("messages", it).add(message) + } + } + + fun pagination(pagination: Pagination) = pagination(JsonField.of(pagination)) + + /** + * Sets [Builder.pagination] to an arbitrary JSON value. + * + * You should usually call [Builder.pagination] with a well-typed [Pagination] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun pagination(pagination: JsonField) = apply { this.pagination = pagination } + + 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 [MessageListResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): MessageListResponse = + MessageListResponse( + chatId, + (messages ?: JsonMissing.of()).map { it.toImmutable() }, + pagination, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): MessageListResponse = apply { + if (validated) { + return@apply + } + + chatId() + messages().ifPresent { it.forEach { it.validate() } } + pagination().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (chatId.asKnown().isPresent) 1 else 0) + + (messages.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (pagination.asKnown().getOrNull()?.validity() ?: 0) + + class Message + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val attachments: JsonField>, + private val direction: JsonField, + private val error: JsonField, + private val externalId: JsonField, + private val internalId: JsonField, + private val messageId: JsonField, + private val protocol: JsonField, + private val reactions: JsonField>, + private val sender: JsonField, + private val status: JsonField, + private val text: JsonField, + private val timeDelivered: JsonField, + private val timeSent: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("attachments") + @ExcludeMissing + attachments: JsonField> = JsonMissing.of(), + @JsonProperty("direction") + @ExcludeMissing + direction: JsonField = JsonMissing.of(), + @JsonProperty("error") @ExcludeMissing error: JsonField = JsonMissing.of(), + @JsonProperty("external_id") + @ExcludeMissing + externalId: JsonField = JsonMissing.of(), + @JsonProperty("internal_id") + @ExcludeMissing + internalId: JsonField = JsonMissing.of(), + @JsonProperty("message_id") + @ExcludeMissing + messageId: JsonField = JsonMissing.of(), + @JsonProperty("protocol") + @ExcludeMissing + protocol: JsonField = JsonMissing.of(), + @JsonProperty("reactions") + @ExcludeMissing + reactions: JsonField> = JsonMissing.of(), + @JsonProperty("sender") @ExcludeMissing sender: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), + @JsonProperty("time_delivered") + @ExcludeMissing + timeDelivered: JsonField = JsonMissing.of(), + @JsonProperty("time_sent") @ExcludeMissing timeSent: JsonField = JsonMissing.of(), + ) : this( + attachments, + direction, + error, + externalId, + internalId, + messageId, + protocol, + reactions, + sender, + status, + text, + timeDelivered, + timeSent, + mutableMapOf(), + ) + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun attachments(): Optional> = attachments.getOptional("attachments") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun direction(): Optional = direction.getOptional("direction") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun error(): Optional = error.getOptional("error") + + /** + * Phone number or email of the contact, or group ID for group messages + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun externalId(): Optional = externalId.getOptional("external_id") + + /** + * Organization phone number (from-number) used for this message + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun internalId(): Optional = internalId.getOptional("internal_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun messageId(): Optional = messageId.getOptional("message_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun protocol(): Optional = protocol.getOptional("protocol") + + /** + * Reactions on this message (tapbacks and emoji reactions) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun reactions(): Optional> = reactions.getOptional("reactions") + + /** + * Sender's phone number or email for inbound group messages. Null for outbound messages and + * 1-1 chats. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun sender(): Optional = sender.getOptional("sender") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun status(): Optional = status.getOptional("status") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun text(): Optional = text.getOptional("text") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun timeDelivered(): Optional = timeDelivered.getOptional("time_delivered") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun timeSent(): Optional = timeSent.getOptional("time_sent") + + /** + * Returns the raw JSON value of [attachments]. + * + * Unlike [attachments], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("attachments") + @ExcludeMissing + fun _attachments(): JsonField> = attachments + + /** + * Returns the raw JSON value of [direction]. + * + * Unlike [direction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("direction") + @ExcludeMissing + fun _direction(): JsonField = direction + + /** + * Returns the raw JSON value of [error]. + * + * Unlike [error], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("error") @ExcludeMissing fun _error(): JsonField = error + + /** + * Returns the raw JSON value of [externalId]. + * + * Unlike [externalId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("external_id") + @ExcludeMissing + fun _externalId(): JsonField = externalId + + /** + * Returns the raw JSON value of [internalId]. + * + * Unlike [internalId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("internal_id") + @ExcludeMissing + fun _internalId(): JsonField = internalId + + /** + * Returns the raw JSON value of [messageId]. + * + * Unlike [messageId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message_id") @ExcludeMissing fun _messageId(): JsonField = messageId + + /** + * Returns the raw JSON value of [protocol]. + * + * Unlike [protocol], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("protocol") @ExcludeMissing fun _protocol(): JsonField = protocol + + /** + * Returns the raw JSON value of [reactions]. + * + * Unlike [reactions], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("reactions") + @ExcludeMissing + fun _reactions(): JsonField> = reactions + + /** + * Returns the raw JSON value of [sender]. + * + * Unlike [sender], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("sender") @ExcludeMissing fun _sender(): JsonField = sender + + /** + * Returns the raw JSON value of [status]. + * + * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + + /** + * Returns the raw JSON value of [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text + + /** + * Returns the raw JSON value of [timeDelivered]. + * + * Unlike [timeDelivered], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("time_delivered") + @ExcludeMissing + fun _timeDelivered(): JsonField = timeDelivered + + /** + * Returns the raw JSON value of [timeSent]. + * + * Unlike [timeSent], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("time_sent") @ExcludeMissing fun _timeSent(): JsonField = timeSent + + @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 [Message]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Message]. */ + class Builder internal constructor() { + + private var attachments: JsonField>? = null + private var direction: JsonField = JsonMissing.of() + private var error: JsonField = JsonMissing.of() + private var externalId: JsonField = JsonMissing.of() + private var internalId: JsonField = JsonMissing.of() + private var messageId: JsonField = JsonMissing.of() + private var protocol: JsonField = JsonMissing.of() + private var reactions: JsonField>? = null + private var sender: JsonField = JsonMissing.of() + private var status: JsonField = JsonMissing.of() + private var text: JsonField = JsonMissing.of() + private var timeDelivered: JsonField = JsonMissing.of() + private var timeSent: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(message: Message) = apply { + attachments = message.attachments.map { it.toMutableList() } + direction = message.direction + error = message.error + externalId = message.externalId + internalId = message.internalId + messageId = message.messageId + protocol = message.protocol + reactions = message.reactions.map { it.toMutableList() } + sender = message.sender + status = message.status + text = message.text + timeDelivered = message.timeDelivered + timeSent = message.timeSent + additionalProperties = message.additionalProperties.toMutableMap() + } + + fun attachments(attachments: List) = attachments(JsonField.of(attachments)) + + /** + * Sets [Builder.attachments] to an arbitrary JSON value. + * + * You should usually call [Builder.attachments] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun attachments(attachments: JsonField>) = apply { + this.attachments = attachments.map { it.toMutableList() } + } + + /** + * Adds a single [JsonValue] to [attachments]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAttachment(attachment: JsonValue) = apply { + attachments = + (attachments ?: JsonField.of(mutableListOf())).also { + checkKnown("attachments", it).add(attachment) + } + } + + fun direction(direction: Direction) = direction(JsonField.of(direction)) + + /** + * Sets [Builder.direction] to an arbitrary JSON value. + * + * You should usually call [Builder.direction] with a well-typed [Direction] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun direction(direction: JsonField) = apply { this.direction = direction } + + fun error(error: String?) = error(JsonField.ofNullable(error)) + + /** Alias for calling [Builder.error] with `error.orElse(null)`. */ + fun error(error: Optional) = error(error.getOrNull()) + + /** + * Sets [Builder.error] to an arbitrary JSON value. + * + * You should usually call [Builder.error] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun error(error: JsonField) = apply { this.error = error } + + /** Phone number or email of the contact, or group ID for group messages */ + fun externalId(externalId: String) = externalId(JsonField.of(externalId)) + + /** + * Sets [Builder.externalId] to an arbitrary JSON value. + * + * You should usually call [Builder.externalId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun externalId(externalId: JsonField) = apply { this.externalId = externalId } + + /** Organization phone number (from-number) used for this message */ + fun internalId(internalId: String?) = internalId(JsonField.ofNullable(internalId)) + + /** Alias for calling [Builder.internalId] with `internalId.orElse(null)`. */ + fun internalId(internalId: Optional) = internalId(internalId.getOrNull()) + + /** + * Sets [Builder.internalId] to an arbitrary JSON value. + * + * You should usually call [Builder.internalId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun internalId(internalId: JsonField) = apply { this.internalId = internalId } + + fun messageId(messageId: String) = messageId(JsonField.of(messageId)) + + /** + * Sets [Builder.messageId] to an arbitrary JSON value. + * + * You should usually call [Builder.messageId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun messageId(messageId: JsonField) = apply { this.messageId = messageId } + + fun protocol(protocol: Protocol?) = protocol(JsonField.ofNullable(protocol)) + + /** Alias for calling [Builder.protocol] with `protocol.orElse(null)`. */ + fun protocol(protocol: Optional) = protocol(protocol.getOrNull()) + + /** + * Sets [Builder.protocol] to an arbitrary JSON value. + * + * You should usually call [Builder.protocol] with a well-typed [Protocol] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun protocol(protocol: JsonField) = apply { this.protocol = protocol } + + /** Reactions on this message (tapbacks and emoji reactions) */ + fun reactions(reactions: List) = reactions(JsonField.of(reactions)) + + /** + * Sets [Builder.reactions] to an arbitrary JSON value. + * + * You should usually call [Builder.reactions] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun reactions(reactions: JsonField>) = apply { + this.reactions = reactions.map { it.toMutableList() } + } + + /** + * Adds a single [Reaction] to [reactions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addReaction(reaction: Reaction) = apply { + reactions = + (reactions ?: JsonField.of(mutableListOf())).also { + checkKnown("reactions", it).add(reaction) + } + } + + /** + * Sender's phone number or email for inbound group messages. Null for outbound messages + * and 1-1 chats. + */ + fun sender(sender: String?) = sender(JsonField.ofNullable(sender)) + + /** Alias for calling [Builder.sender] with `sender.orElse(null)`. */ + fun sender(sender: Optional) = sender(sender.getOrNull()) + + /** + * Sets [Builder.sender] to an arbitrary JSON value. + * + * You should usually call [Builder.sender] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun sender(sender: JsonField) = apply { this.sender = sender } + + fun status(status: Status?) = status(JsonField.ofNullable(status)) + + /** Alias for calling [Builder.status] with `status.orElse(null)`. */ + fun status(status: Optional) = status(status.getOrNull()) + + /** + * Sets [Builder.status] to an arbitrary JSON value. + * + * You should usually call [Builder.status] with a well-typed [Status] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun status(status: JsonField) = apply { this.status = status } + + fun text(text: String?) = text(JsonField.ofNullable(text)) + + /** Alias for calling [Builder.text] with `text.orElse(null)`. */ + fun text(text: Optional) = text(text.getOrNull()) + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun text(text: JsonField) = apply { this.text = text } + + fun timeDelivered(timeDelivered: Long?) = + timeDelivered(JsonField.ofNullable(timeDelivered)) + + /** + * Alias for [Builder.timeDelivered]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun timeDelivered(timeDelivered: Long) = timeDelivered(timeDelivered as Long?) + + /** Alias for calling [Builder.timeDelivered] with `timeDelivered.orElse(null)`. */ + fun timeDelivered(timeDelivered: Optional) = + timeDelivered(timeDelivered.getOrNull()) + + /** + * Sets [Builder.timeDelivered] to an arbitrary JSON value. + * + * You should usually call [Builder.timeDelivered] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun timeDelivered(timeDelivered: JsonField) = apply { + this.timeDelivered = timeDelivered + } + + fun timeSent(timeSent: Long) = timeSent(JsonField.of(timeSent)) + + /** + * Sets [Builder.timeSent] to an arbitrary JSON value. + * + * You should usually call [Builder.timeSent] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun timeSent(timeSent: JsonField) = apply { this.timeSent = timeSent } + + 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 [Message]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Message = + Message( + (attachments ?: JsonMissing.of()).map { it.toImmutable() }, + direction, + error, + externalId, + internalId, + messageId, + protocol, + (reactions ?: JsonMissing.of()).map { it.toImmutable() }, + sender, + status, + text, + timeDelivered, + timeSent, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Message = apply { + if (validated) { + return@apply + } + + attachments() + direction().ifPresent { it.validate() } + error() + externalId() + internalId() + messageId() + protocol().ifPresent { it.validate() } + reactions().ifPresent { it.forEach { it.validate() } } + sender() + status().ifPresent { it.validate() } + text() + timeDelivered() + timeSent() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 = + (attachments.asKnown().getOrNull()?.size ?: 0) + + (direction.asKnown().getOrNull()?.validity() ?: 0) + + (if (error.asKnown().isPresent) 1 else 0) + + (if (externalId.asKnown().isPresent) 1 else 0) + + (if (internalId.asKnown().isPresent) 1 else 0) + + (if (messageId.asKnown().isPresent) 1 else 0) + + (protocol.asKnown().getOrNull()?.validity() ?: 0) + + (reactions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (sender.asKnown().isPresent) 1 else 0) + + (status.asKnown().getOrNull()?.validity() ?: 0) + + (if (text.asKnown().isPresent) 1 else 0) + + (if (timeDelivered.asKnown().isPresent) 1 else 0) + + (if (timeSent.asKnown().isPresent) 1 else 0) + + class Direction @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val INBOUND = of("inbound") + + @JvmField val OUTBOUND = of("outbound") + + @JvmStatic fun of(value: String) = Direction(JsonField.of(value)) + } + + /** An enum containing [Direction]'s known values. */ + enum class Known { + INBOUND, + OUTBOUND, + } + + /** + * An enum containing [Direction]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Direction] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + INBOUND, + OUTBOUND, + /** + * An enum member indicating that [Direction] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + INBOUND -> Value.INBOUND + OUTBOUND -> Value.OUTBOUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + INBOUND -> Known.INBOUND + OUTBOUND -> Known.OUTBOUND + else -> throw BlooioInvalidDataException("Unknown Direction: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + BlooioInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Direction = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Direction && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class Protocol @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val IMESSAGE = of("imessage") + + @JvmField val SMS = of("sms") + + @JvmField val RCS = of("rcs") + + @JvmField val NON_IMESSAGE = of("non-imessage") + + @JvmStatic fun of(value: String) = Protocol(JsonField.of(value)) + } + + /** An enum containing [Protocol]'s known values. */ + enum class Known { + IMESSAGE, + SMS, + RCS, + NON_IMESSAGE, + } + + /** + * An enum containing [Protocol]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Protocol] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + IMESSAGE, + SMS, + RCS, + NON_IMESSAGE, + /** + * An enum member indicating that [Protocol] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + IMESSAGE -> Value.IMESSAGE + SMS -> Value.SMS + RCS -> Value.RCS + NON_IMESSAGE -> Value.NON_IMESSAGE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + IMESSAGE -> Known.IMESSAGE + SMS -> Known.SMS + RCS -> Known.RCS + NON_IMESSAGE -> Known.NON_IMESSAGE + else -> throw BlooioInvalidDataException("Unknown Protocol: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + BlooioInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Protocol = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Protocol && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val PENDING = of("pending") + + @JvmField val QUEUED = of("queued") + + @JvmField val SENT = of("sent") + + @JvmField val DELIVERED = of("delivered") + + @JvmField val FAILED = of("failed") + + @JvmField val CANCELLATION_REQUESTED = of("cancellation_requested") + + @JvmField val CANCELLED = of("cancelled") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + PENDING, + QUEUED, + SENT, + DELIVERED, + FAILED, + CANCELLATION_REQUESTED, + CANCELLED, + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + PENDING, + QUEUED, + SENT, + DELIVERED, + FAILED, + CANCELLATION_REQUESTED, + CANCELLED, + /** + * An enum member indicating that [Status] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + PENDING -> Value.PENDING + QUEUED -> Value.QUEUED + SENT -> Value.SENT + DELIVERED -> Value.DELIVERED + FAILED -> Value.FAILED + CANCELLATION_REQUESTED -> Value.CANCELLATION_REQUESTED + CANCELLED -> Value.CANCELLED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + PENDING -> Known.PENDING + QUEUED -> Known.QUEUED + SENT -> Known.SENT + DELIVERED -> Known.DELIVERED + FAILED -> Known.FAILED + CANCELLATION_REQUESTED -> Known.CANCELLATION_REQUESTED + CANCELLED -> Known.CANCELLED + else -> throw BlooioInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + BlooioInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Status && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Message && + attachments == other.attachments && + direction == other.direction && + error == other.error && + externalId == other.externalId && + internalId == other.internalId && + messageId == other.messageId && + protocol == other.protocol && + reactions == other.reactions && + sender == other.sender && + status == other.status && + text == other.text && + timeDelivered == other.timeDelivered && + timeSent == other.timeSent && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + attachments, + direction, + error, + externalId, + internalId, + messageId, + protocol, + reactions, + sender, + status, + text, + timeDelivered, + timeSent, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Message{attachments=$attachments, direction=$direction, error=$error, externalId=$externalId, internalId=$internalId, messageId=$messageId, protocol=$protocol, reactions=$reactions, sender=$sender, status=$status, text=$text, timeDelivered=$timeDelivered, timeSent=$timeSent, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is MessageListResponse && + chatId == other.chatId && + messages == other.messages && + pagination == other.pagination && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(chatId, messages, pagination, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "MessageListResponse{chatId=$chatId, messages=$messages, pagination=$pagination, additionalProperties=$additionalProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageReactParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageReactParams.kt new file mode 100644 index 0000000..abd189b --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageReactParams.kt @@ -0,0 +1,695 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.messages + +import com.blooio.api.core.Enum +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.core.Params +import com.blooio.api.core.checkRequired +import com.blooio.api.core.http.Headers +import com.blooio.api.core.http.QueryParams +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Add or remove a reaction to a message. Supports classic iMessage tapbacks (love, like, dislike, + * laugh, emphasize, question) and emoji reactions (e.g. +😂, -😂). + * + * The messageId can be an explicit message ID (e.g., msg_xxx) or a relative index (-1 for last + * message, -2 for second-to-last, etc.). When using relative indices, you can optionally filter by + * message direction (inbound/outbound only). + * + * Emoji reactions require macOS 14 (Sonoma) or later on the device. + */ +class MessageReactParams +private constructor( + private val chatId: String, + private val messageId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun chatId(): String = chatId + + fun messageId(): Optional = Optional.ofNullable(messageId) + + /** + * The reaction to add or remove. Must be prefixed with `+` to add or `-` to remove. + * + * **Classic tapbacks:** `+love`, `-love`, `+like`, `-like`, `+dislike`, `-dislike`, `+laugh`, + * `-laugh`, `+emphasize`, `-emphasize`, `+question`, `-question` + * + * **Emoji reactions:** Any emoji prefixed with `+` or `-` (e.g. `+😂`, `-😂`, `+👍`, `-🔥`). + * Emoji reactions require macOS 14 (Sonoma) or later on the device. + * + * @throws BlooioInvalidDataException 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 reaction(): String = body.reaction() + + /** + * Filter by message direction (only used when messageId is a relative index like -1, -2) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun direction(): Optional = body.direction() + + /** + * Returns the raw JSON value of [reaction]. + * + * Unlike [reaction], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _reaction(): JsonField = body._reaction() + + /** + * Returns the raw JSON value of [direction]. + * + * Unlike [direction], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _direction(): JsonField = body._direction() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + /** 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 [MessageReactParams]. + * + * The following fields are required: + * ```java + * .chatId() + * .reaction() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [MessageReactParams]. */ + class Builder internal constructor() { + + private var chatId: String? = null + private var messageId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(messageReactParams: MessageReactParams) = apply { + chatId = messageReactParams.chatId + messageId = messageReactParams.messageId + body = messageReactParams.body.toBuilder() + additionalHeaders = messageReactParams.additionalHeaders.toBuilder() + additionalQueryParams = messageReactParams.additionalQueryParams.toBuilder() + } + + fun chatId(chatId: String) = apply { this.chatId = chatId } + + fun messageId(messageId: String?) = apply { this.messageId = messageId } + + /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ + fun messageId(messageId: Optional) = messageId(messageId.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [reaction] + * - [direction] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** + * The reaction to add or remove. Must be prefixed with `+` to add or `-` to remove. + * + * **Classic tapbacks:** `+love`, `-love`, `+like`, `-like`, `+dislike`, `-dislike`, + * `+laugh`, `-laugh`, `+emphasize`, `-emphasize`, `+question`, `-question` + * + * **Emoji reactions:** Any emoji prefixed with `+` or `-` (e.g. `+😂`, `-😂`, `+👍`, + * `-🔥`). Emoji reactions require macOS 14 (Sonoma) or later on the device. + */ + fun reaction(reaction: String) = apply { body.reaction(reaction) } + + /** + * Sets [Builder.reaction] to an arbitrary JSON value. + * + * You should usually call [Builder.reaction] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun reaction(reaction: JsonField) = apply { body.reaction(reaction) } + + /** + * Filter by message direction (only used when messageId is a relative index like -1, -2) + */ + fun direction(direction: Direction) = apply { body.direction(direction) } + + /** + * Sets [Builder.direction] to an arbitrary JSON value. + * + * You should usually call [Builder.direction] with a well-typed [Direction] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun direction(direction: JsonField) = apply { body.direction(direction) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + 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 [MessageReactParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .chatId() + * .reaction() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): MessageReactParams = + MessageReactParams( + checkRequired("chatId", chatId), + messageId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> chatId + 1 -> messageId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val reaction: JsonField, + private val direction: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("reaction") + @ExcludeMissing + reaction: JsonField = JsonMissing.of(), + @JsonProperty("direction") + @ExcludeMissing + direction: JsonField = JsonMissing.of(), + ) : this(reaction, direction, mutableMapOf()) + + /** + * The reaction to add or remove. Must be prefixed with `+` to add or `-` to remove. + * + * **Classic tapbacks:** `+love`, `-love`, `+like`, `-like`, `+dislike`, `-dislike`, + * `+laugh`, `-laugh`, `+emphasize`, `-emphasize`, `+question`, `-question` + * + * **Emoji reactions:** Any emoji prefixed with `+` or `-` (e.g. `+😂`, `-😂`, `+👍`, + * `-🔥`). Emoji reactions require macOS 14 (Sonoma) or later on the device. + * + * @throws BlooioInvalidDataException 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 reaction(): String = reaction.getRequired("reaction") + + /** + * Filter by message direction (only used when messageId is a relative index like -1, -2) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun direction(): Optional = direction.getOptional("direction") + + /** + * Returns the raw JSON value of [reaction]. + * + * Unlike [reaction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("reaction") @ExcludeMissing fun _reaction(): JsonField = reaction + + /** + * Returns the raw JSON value of [direction]. + * + * Unlike [direction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("direction") + @ExcludeMissing + fun _direction(): JsonField = direction + + @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 [Body]. + * + * The following fields are required: + * ```java + * .reaction() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var reaction: JsonField? = null + private var direction: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + reaction = body.reaction + direction = body.direction + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** + * The reaction to add or remove. Must be prefixed with `+` to add or `-` to remove. + * + * **Classic tapbacks:** `+love`, `-love`, `+like`, `-like`, `+dislike`, `-dislike`, + * `+laugh`, `-laugh`, `+emphasize`, `-emphasize`, `+question`, `-question` + * + * **Emoji reactions:** Any emoji prefixed with `+` or `-` (e.g. `+😂`, `-😂`, `+👍`, + * `-🔥`). Emoji reactions require macOS 14 (Sonoma) or later on the device. + */ + fun reaction(reaction: String) = reaction(JsonField.of(reaction)) + + /** + * Sets [Builder.reaction] to an arbitrary JSON value. + * + * You should usually call [Builder.reaction] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun reaction(reaction: JsonField) = apply { this.reaction = reaction } + + /** + * Filter by message direction (only used when messageId is a relative index like -1, + * -2) + */ + fun direction(direction: Direction) = direction(JsonField.of(direction)) + + /** + * Sets [Builder.direction] to an arbitrary JSON value. + * + * You should usually call [Builder.direction] with a well-typed [Direction] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun direction(direction: JsonField) = apply { this.direction = direction } + + 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 [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .reaction() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("reaction", reaction), + direction, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + reaction() + direction().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (reaction.asKnown().isPresent) 1 else 0) + + (direction.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + reaction == other.reaction && + direction == other.direction && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(reaction, direction, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{reaction=$reaction, direction=$direction, additionalProperties=$additionalProperties}" + } + + /** Filter by message direction (only used when messageId is a relative index like -1, -2) */ + class Direction @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val INBOUND = of("inbound") + + @JvmField val OUTBOUND = of("outbound") + + @JvmStatic fun of(value: String) = Direction(JsonField.of(value)) + } + + /** An enum containing [Direction]'s known values. */ + enum class Known { + INBOUND, + OUTBOUND, + } + + /** + * An enum containing [Direction]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Direction] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + INBOUND, + OUTBOUND, + /** + * An enum member indicating that [Direction] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + INBOUND -> Value.INBOUND + OUTBOUND -> Value.OUTBOUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + INBOUND -> Known.INBOUND + OUTBOUND -> Known.OUTBOUND + else -> throw BlooioInvalidDataException("Unknown Direction: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Direction = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Direction && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is MessageReactParams && + chatId == other.chatId && + messageId == other.messageId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(chatId, messageId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "MessageReactParams{chatId=$chatId, messageId=$messageId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageReactResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageReactResponse.kt new file mode 100644 index 0000000..7d92561 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageReactResponse.kt @@ -0,0 +1,398 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.messages + +import com.blooio.api.core.Enum +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class MessageReactResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val action: JsonField, + private val messageId: JsonField, + private val reaction: JsonField, + private val success: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("action") @ExcludeMissing action: JsonField = JsonMissing.of(), + @JsonProperty("message_id") @ExcludeMissing messageId: JsonField = JsonMissing.of(), + @JsonProperty("reaction") @ExcludeMissing reaction: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + ) : this(action, messageId, reaction, success, mutableMapOf()) + + /** + * The action that was performed + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun action(): Optional = action.getOptional("action") + + /** + * The ID of the message that was reacted to + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun messageId(): Optional = messageId.getOptional("message_id") + + /** + * The reaction that was added or removed. For classic tapbacks: love, like, dislike, laugh, + * emphasize, question. For emoji reactions: the emoji character (e.g. 😂, 👍, 🔥). + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun reaction(): Optional = reaction.getOptional("reaction") + + /** + * Whether the reaction was sent successfully + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun success(): Optional = success.getOptional("success") + + /** + * Returns the raw JSON value of [action]. + * + * Unlike [action], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("action") @ExcludeMissing fun _action(): JsonField = action + + /** + * Returns the raw JSON value of [messageId]. + * + * Unlike [messageId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message_id") @ExcludeMissing fun _messageId(): JsonField = messageId + + /** + * Returns the raw JSON value of [reaction]. + * + * Unlike [reaction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("reaction") @ExcludeMissing fun _reaction(): JsonField = reaction + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + + @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 [MessageReactResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [MessageReactResponse]. */ + class Builder internal constructor() { + + private var action: JsonField = JsonMissing.of() + private var messageId: JsonField = JsonMissing.of() + private var reaction: JsonField = JsonMissing.of() + private var success: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(messageReactResponse: MessageReactResponse) = apply { + action = messageReactResponse.action + messageId = messageReactResponse.messageId + reaction = messageReactResponse.reaction + success = messageReactResponse.success + additionalProperties = messageReactResponse.additionalProperties.toMutableMap() + } + + /** The action that was performed */ + fun action(action: Action) = action(JsonField.of(action)) + + /** + * Sets [Builder.action] to an arbitrary JSON value. + * + * You should usually call [Builder.action] with a well-typed [Action] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun action(action: JsonField) = apply { this.action = action } + + /** The ID of the message that was reacted to */ + fun messageId(messageId: String) = messageId(JsonField.of(messageId)) + + /** + * Sets [Builder.messageId] to an arbitrary JSON value. + * + * You should usually call [Builder.messageId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun messageId(messageId: JsonField) = apply { this.messageId = messageId } + + /** + * The reaction that was added or removed. For classic tapbacks: love, like, dislike, laugh, + * emphasize, question. For emoji reactions: the emoji character (e.g. 😂, 👍, 🔥). + */ + fun reaction(reaction: String) = reaction(JsonField.of(reaction)) + + /** + * Sets [Builder.reaction] to an arbitrary JSON value. + * + * You should usually call [Builder.reaction] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun reaction(reaction: JsonField) = apply { this.reaction = reaction } + + /** Whether the reaction was sent successfully */ + fun success(success: Boolean) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + + 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 [MessageReactResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): MessageReactResponse = + MessageReactResponse( + action, + messageId, + reaction, + success, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): MessageReactResponse = apply { + if (validated) { + return@apply + } + + action().ifPresent { it.validate() } + messageId() + reaction() + success() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 = + (action.asKnown().getOrNull()?.validity() ?: 0) + + (if (messageId.asKnown().isPresent) 1 else 0) + + (if (reaction.asKnown().isPresent) 1 else 0) + + (if (success.asKnown().isPresent) 1 else 0) + + /** The action that was performed */ + class Action @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val ADD = of("add") + + @JvmField val REMOVE = of("remove") + + @JvmStatic fun of(value: String) = Action(JsonField.of(value)) + } + + /** An enum containing [Action]'s known values. */ + enum class Known { + ADD, + REMOVE, + } + + /** + * An enum containing [Action]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Action] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + ADD, + REMOVE, + /** An enum member indicating that [Action] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + ADD -> Value.ADD + REMOVE -> Value.REMOVE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + ADD -> Known.ADD + REMOVE -> Known.REMOVE + else -> throw BlooioInvalidDataException("Unknown Action: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Action = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Action && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is MessageReactResponse && + action == other.action && + messageId == other.messageId && + reaction == other.reaction && + success == other.success && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(action, messageId, reaction, success, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "MessageReactResponse{action=$action, messageId=$messageId, reaction=$reaction, success=$success, additionalProperties=$additionalProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageRetrieveParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageRetrieveParams.kt similarity index 84% rename from blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageRetrieveParams.kt rename to blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageRetrieveParams.kt index aeea016..bcba649 100644 --- a/blooio-java-core/src/main/kotlin/com/blooio/api/models/messages/MessageRetrieveParams.kt +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageRetrieveParams.kt @@ -1,25 +1,26 @@ // File generated from our OpenAPI spec by Stainless. -package com.blooio.api.models.messages +package com.blooio.api.models.chats.messages import com.blooio.api.core.Params +import com.blooio.api.core.checkRequired import com.blooio.api.core.http.Headers import com.blooio.api.core.http.QueryParams import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull -/** - * Retrieve full message metadata including direction, protocol, text length, attachments count, - * timestamps, current status, and original metadata. - */ +/** Get details for a specific message. */ class MessageRetrieveParams private constructor( + private val chatId: String, private val messageId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { + fun chatId(): String = chatId + fun messageId(): Optional = Optional.ofNullable(messageId) /** Additional headers to send with the request. */ @@ -32,26 +33,35 @@ private constructor( companion object { - @JvmStatic fun none(): MessageRetrieveParams = builder().build() - - /** Returns a mutable builder for constructing an instance of [MessageRetrieveParams]. */ + /** + * Returns a mutable builder for constructing an instance of [MessageRetrieveParams]. + * + * The following fields are required: + * ```java + * .chatId() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [MessageRetrieveParams]. */ class Builder internal constructor() { + private var chatId: String? = null private var messageId: String? = null private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @JvmSynthetic internal fun from(messageRetrieveParams: MessageRetrieveParams) = apply { + chatId = messageRetrieveParams.chatId messageId = messageRetrieveParams.messageId additionalHeaders = messageRetrieveParams.additionalHeaders.toBuilder() additionalQueryParams = messageRetrieveParams.additionalQueryParams.toBuilder() } + fun chatId(chatId: String) = apply { this.chatId = chatId } + fun messageId(messageId: String?) = apply { this.messageId = messageId } /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ @@ -159,9 +169,17 @@ private constructor( * Returns an immutable instance of [MessageRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .chatId() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): MessageRetrieveParams = MessageRetrieveParams( + checkRequired("chatId", chatId), messageId, additionalHeaders.build(), additionalQueryParams.build(), @@ -170,7 +188,8 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> messageId ?: "" + 0 -> chatId + 1 -> messageId ?: "" else -> "" } @@ -184,13 +203,15 @@ private constructor( } return other is MessageRetrieveParams && + chatId == other.chatId && messageId == other.messageId && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams } - override fun hashCode(): Int = Objects.hash(messageId, additionalHeaders, additionalQueryParams) + override fun hashCode(): Int = + Objects.hash(chatId, messageId, additionalHeaders, additionalQueryParams) override fun toString() = - "MessageRetrieveParams{messageId=$messageId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "MessageRetrieveParams{chatId=$chatId, messageId=$messageId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageRetrieveResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageRetrieveResponse.kt new file mode 100644 index 0000000..3d96814 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageRetrieveResponse.kt @@ -0,0 +1,1332 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.messages + +import com.blooio.api.core.Enum +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.core.checkKnown +import com.blooio.api.core.toImmutable +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class MessageRetrieveResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val attachments: JsonField>, + private val chatId: JsonField, + private val contact: JsonField, + private val direction: JsonField, + private val error: JsonField, + private val internalId: JsonField, + private val messageId: JsonField, + private val protocol: JsonField, + private val reactions: JsonField>, + private val sender: JsonField, + private val status: JsonField, + private val text: JsonField, + private val timeDelivered: JsonField, + private val timeSent: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("attachments") + @ExcludeMissing + attachments: JsonField> = JsonMissing.of(), + @JsonProperty("chat_id") @ExcludeMissing chatId: JsonField = JsonMissing.of(), + @JsonProperty("contact") @ExcludeMissing contact: JsonField = JsonMissing.of(), + @JsonProperty("direction") + @ExcludeMissing + direction: JsonField = JsonMissing.of(), + @JsonProperty("error") @ExcludeMissing error: JsonField = JsonMissing.of(), + @JsonProperty("internal_id") + @ExcludeMissing + internalId: JsonField = JsonMissing.of(), + @JsonProperty("message_id") @ExcludeMissing messageId: JsonField = JsonMissing.of(), + @JsonProperty("protocol") @ExcludeMissing protocol: JsonField = JsonMissing.of(), + @JsonProperty("reactions") + @ExcludeMissing + reactions: JsonField> = JsonMissing.of(), + @JsonProperty("sender") @ExcludeMissing sender: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), + @JsonProperty("time_delivered") + @ExcludeMissing + timeDelivered: JsonField = JsonMissing.of(), + @JsonProperty("time_sent") @ExcludeMissing timeSent: JsonField = JsonMissing.of(), + ) : this( + attachments, + chatId, + contact, + direction, + error, + internalId, + messageId, + protocol, + reactions, + sender, + status, + text, + timeDelivered, + timeSent, + mutableMapOf(), + ) + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun attachments(): Optional> = attachments.getOptional("attachments") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun chatId(): Optional = chatId.getOptional("chat_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun contact(): Optional = contact.getOptional("contact") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun direction(): Optional = direction.getOptional("direction") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun error(): Optional = error.getOptional("error") + + /** + * Organization phone number (from-number) used for this message + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun internalId(): Optional = internalId.getOptional("internal_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun messageId(): Optional = messageId.getOptional("message_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun protocol(): Optional = protocol.getOptional("protocol") + + /** + * Reactions on this message (tapbacks and emoji reactions) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun reactions(): Optional> = reactions.getOptional("reactions") + + /** + * Sender's phone number or email for inbound group messages. Null for outbound messages and 1-1 + * chats. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun sender(): Optional = sender.getOptional("sender") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun status(): Optional = status.getOptional("status") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun text(): Optional = text.getOptional("text") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun timeDelivered(): Optional = timeDelivered.getOptional("time_delivered") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun timeSent(): Optional = timeSent.getOptional("time_sent") + + /** + * Returns the raw JSON value of [attachments]. + * + * Unlike [attachments], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("attachments") + @ExcludeMissing + fun _attachments(): JsonField> = attachments + + /** + * Returns the raw JSON value of [chatId]. + * + * Unlike [chatId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("chat_id") @ExcludeMissing fun _chatId(): JsonField = chatId + + /** + * Returns the raw JSON value of [contact]. + * + * Unlike [contact], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("contact") @ExcludeMissing fun _contact(): JsonField = contact + + /** + * Returns the raw JSON value of [direction]. + * + * Unlike [direction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("direction") @ExcludeMissing fun _direction(): JsonField = direction + + /** + * Returns the raw JSON value of [error]. + * + * Unlike [error], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("error") @ExcludeMissing fun _error(): JsonField = error + + /** + * Returns the raw JSON value of [internalId]. + * + * Unlike [internalId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("internal_id") @ExcludeMissing fun _internalId(): JsonField = internalId + + /** + * Returns the raw JSON value of [messageId]. + * + * Unlike [messageId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message_id") @ExcludeMissing fun _messageId(): JsonField = messageId + + /** + * Returns the raw JSON value of [protocol]. + * + * Unlike [protocol], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("protocol") @ExcludeMissing fun _protocol(): JsonField = protocol + + /** + * Returns the raw JSON value of [reactions]. + * + * Unlike [reactions], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("reactions") + @ExcludeMissing + fun _reactions(): JsonField> = reactions + + /** + * Returns the raw JSON value of [sender]. + * + * Unlike [sender], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("sender") @ExcludeMissing fun _sender(): JsonField = sender + + /** + * Returns the raw JSON value of [status]. + * + * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + + /** + * Returns the raw JSON value of [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text + + /** + * Returns the raw JSON value of [timeDelivered]. + * + * Unlike [timeDelivered], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("time_delivered") + @ExcludeMissing + fun _timeDelivered(): JsonField = timeDelivered + + /** + * Returns the raw JSON value of [timeSent]. + * + * Unlike [timeSent], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("time_sent") @ExcludeMissing fun _timeSent(): JsonField = timeSent + + @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 [MessageRetrieveResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [MessageRetrieveResponse]. */ + class Builder internal constructor() { + + private var attachments: JsonField>? = null + private var chatId: JsonField = JsonMissing.of() + private var contact: JsonField = JsonMissing.of() + private var direction: JsonField = JsonMissing.of() + private var error: JsonField = JsonMissing.of() + private var internalId: JsonField = JsonMissing.of() + private var messageId: JsonField = JsonMissing.of() + private var protocol: JsonField = JsonMissing.of() + private var reactions: JsonField>? = null + private var sender: JsonField = JsonMissing.of() + private var status: JsonField = JsonMissing.of() + private var text: JsonField = JsonMissing.of() + private var timeDelivered: JsonField = JsonMissing.of() + private var timeSent: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(messageRetrieveResponse: MessageRetrieveResponse) = apply { + attachments = messageRetrieveResponse.attachments.map { it.toMutableList() } + chatId = messageRetrieveResponse.chatId + contact = messageRetrieveResponse.contact + direction = messageRetrieveResponse.direction + error = messageRetrieveResponse.error + internalId = messageRetrieveResponse.internalId + messageId = messageRetrieveResponse.messageId + protocol = messageRetrieveResponse.protocol + reactions = messageRetrieveResponse.reactions.map { it.toMutableList() } + sender = messageRetrieveResponse.sender + status = messageRetrieveResponse.status + text = messageRetrieveResponse.text + timeDelivered = messageRetrieveResponse.timeDelivered + timeSent = messageRetrieveResponse.timeSent + additionalProperties = messageRetrieveResponse.additionalProperties.toMutableMap() + } + + fun attachments(attachments: List) = attachments(JsonField.of(attachments)) + + /** + * Sets [Builder.attachments] to an arbitrary JSON value. + * + * You should usually call [Builder.attachments] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun attachments(attachments: JsonField>) = apply { + this.attachments = attachments.map { it.toMutableList() } + } + + /** + * Adds a single [JsonValue] to [attachments]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAttachment(attachment: JsonValue) = apply { + attachments = + (attachments ?: JsonField.of(mutableListOf())).also { + checkKnown("attachments", it).add(attachment) + } + } + + fun chatId(chatId: String) = chatId(JsonField.of(chatId)) + + /** + * Sets [Builder.chatId] to an arbitrary JSON value. + * + * You should usually call [Builder.chatId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun chatId(chatId: JsonField) = apply { this.chatId = chatId } + + fun contact(contact: Contact?) = contact(JsonField.ofNullable(contact)) + + /** Alias for calling [Builder.contact] with `contact.orElse(null)`. */ + fun contact(contact: Optional) = contact(contact.getOrNull()) + + /** + * Sets [Builder.contact] to an arbitrary JSON value. + * + * You should usually call [Builder.contact] with a well-typed [Contact] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun contact(contact: JsonField) = apply { this.contact = contact } + + fun direction(direction: Direction) = direction(JsonField.of(direction)) + + /** + * Sets [Builder.direction] to an arbitrary JSON value. + * + * You should usually call [Builder.direction] with a well-typed [Direction] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun direction(direction: JsonField) = apply { this.direction = direction } + + fun error(error: String?) = error(JsonField.ofNullable(error)) + + /** Alias for calling [Builder.error] with `error.orElse(null)`. */ + fun error(error: Optional) = error(error.getOrNull()) + + /** + * Sets [Builder.error] to an arbitrary JSON value. + * + * You should usually call [Builder.error] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun error(error: JsonField) = apply { this.error = error } + + /** Organization phone number (from-number) used for this message */ + fun internalId(internalId: String?) = internalId(JsonField.ofNullable(internalId)) + + /** Alias for calling [Builder.internalId] with `internalId.orElse(null)`. */ + fun internalId(internalId: Optional) = internalId(internalId.getOrNull()) + + /** + * Sets [Builder.internalId] to an arbitrary JSON value. + * + * You should usually call [Builder.internalId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun internalId(internalId: JsonField) = apply { this.internalId = internalId } + + fun messageId(messageId: String) = messageId(JsonField.of(messageId)) + + /** + * Sets [Builder.messageId] to an arbitrary JSON value. + * + * You should usually call [Builder.messageId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun messageId(messageId: JsonField) = apply { this.messageId = messageId } + + fun protocol(protocol: Protocol?) = protocol(JsonField.ofNullable(protocol)) + + /** Alias for calling [Builder.protocol] with `protocol.orElse(null)`. */ + fun protocol(protocol: Optional) = protocol(protocol.getOrNull()) + + /** + * Sets [Builder.protocol] to an arbitrary JSON value. + * + * You should usually call [Builder.protocol] with a well-typed [Protocol] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun protocol(protocol: JsonField) = apply { this.protocol = protocol } + + /** Reactions on this message (tapbacks and emoji reactions) */ + fun reactions(reactions: List) = reactions(JsonField.of(reactions)) + + /** + * Sets [Builder.reactions] to an arbitrary JSON value. + * + * You should usually call [Builder.reactions] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun reactions(reactions: JsonField>) = apply { + this.reactions = reactions.map { it.toMutableList() } + } + + /** + * Adds a single [Reaction] to [reactions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addReaction(reaction: Reaction) = apply { + reactions = + (reactions ?: JsonField.of(mutableListOf())).also { + checkKnown("reactions", it).add(reaction) + } + } + + /** + * Sender's phone number or email for inbound group messages. Null for outbound messages and + * 1-1 chats. + */ + fun sender(sender: String?) = sender(JsonField.ofNullable(sender)) + + /** Alias for calling [Builder.sender] with `sender.orElse(null)`. */ + fun sender(sender: Optional) = sender(sender.getOrNull()) + + /** + * Sets [Builder.sender] to an arbitrary JSON value. + * + * You should usually call [Builder.sender] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun sender(sender: JsonField) = apply { this.sender = sender } + + fun status(status: Status?) = status(JsonField.ofNullable(status)) + + /** Alias for calling [Builder.status] with `status.orElse(null)`. */ + fun status(status: Optional) = status(status.getOrNull()) + + /** + * Sets [Builder.status] to an arbitrary JSON value. + * + * You should usually call [Builder.status] with a well-typed [Status] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun status(status: JsonField) = apply { this.status = status } + + fun text(text: String?) = text(JsonField.ofNullable(text)) + + /** Alias for calling [Builder.text] with `text.orElse(null)`. */ + fun text(text: Optional) = text(text.getOrNull()) + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun text(text: JsonField) = apply { this.text = text } + + fun timeDelivered(timeDelivered: Long?) = timeDelivered(JsonField.ofNullable(timeDelivered)) + + /** + * Alias for [Builder.timeDelivered]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun timeDelivered(timeDelivered: Long) = timeDelivered(timeDelivered as Long?) + + /** Alias for calling [Builder.timeDelivered] with `timeDelivered.orElse(null)`. */ + fun timeDelivered(timeDelivered: Optional) = timeDelivered(timeDelivered.getOrNull()) + + /** + * Sets [Builder.timeDelivered] to an arbitrary JSON value. + * + * You should usually call [Builder.timeDelivered] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun timeDelivered(timeDelivered: JsonField) = apply { + this.timeDelivered = timeDelivered + } + + fun timeSent(timeSent: Long) = timeSent(JsonField.of(timeSent)) + + /** + * Sets [Builder.timeSent] to an arbitrary JSON value. + * + * You should usually call [Builder.timeSent] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun timeSent(timeSent: JsonField) = apply { this.timeSent = timeSent } + + 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 [MessageRetrieveResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): MessageRetrieveResponse = + MessageRetrieveResponse( + (attachments ?: JsonMissing.of()).map { it.toImmutable() }, + chatId, + contact, + direction, + error, + internalId, + messageId, + protocol, + (reactions ?: JsonMissing.of()).map { it.toImmutable() }, + sender, + status, + text, + timeDelivered, + timeSent, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): MessageRetrieveResponse = apply { + if (validated) { + return@apply + } + + attachments() + chatId() + contact().ifPresent { it.validate() } + direction().ifPresent { it.validate() } + error() + internalId() + messageId() + protocol().ifPresent { it.validate() } + reactions().ifPresent { it.forEach { it.validate() } } + sender() + status().ifPresent { it.validate() } + text() + timeDelivered() + timeSent() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 = + (attachments.asKnown().getOrNull()?.size ?: 0) + + (if (chatId.asKnown().isPresent) 1 else 0) + + (contact.asKnown().getOrNull()?.validity() ?: 0) + + (direction.asKnown().getOrNull()?.validity() ?: 0) + + (if (error.asKnown().isPresent) 1 else 0) + + (if (internalId.asKnown().isPresent) 1 else 0) + + (if (messageId.asKnown().isPresent) 1 else 0) + + (protocol.asKnown().getOrNull()?.validity() ?: 0) + + (reactions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (sender.asKnown().isPresent) 1 else 0) + + (status.asKnown().getOrNull()?.validity() ?: 0) + + (if (text.asKnown().isPresent) 1 else 0) + + (if (timeDelivered.asKnown().isPresent) 1 else 0) + + (if (timeSent.asKnown().isPresent) 1 else 0) + + class Contact + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val contactId: JsonField, + private val identifier: JsonField, + private val name: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("contact_id") + @ExcludeMissing + contactId: JsonField = JsonMissing.of(), + @JsonProperty("identifier") + @ExcludeMissing + identifier: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(contactId, identifier, name, mutableMapOf()) + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun contactId(): Optional = contactId.getOptional("contact_id") + + /** + * The contact's phone number or email + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun identifier(): Optional = identifier.getOptional("identifier") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * Returns the raw JSON value of [contactId]. + * + * Unlike [contactId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("contact_id") @ExcludeMissing fun _contactId(): JsonField = contactId + + /** + * Returns the raw JSON value of [identifier]. + * + * Unlike [identifier], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("identifier") + @ExcludeMissing + fun _identifier(): JsonField = identifier + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + @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 [Contact]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Contact]. */ + class Builder internal constructor() { + + private var contactId: JsonField = JsonMissing.of() + private var identifier: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(contact: Contact) = apply { + contactId = contact.contactId + identifier = contact.identifier + name = contact.name + additionalProperties = contact.additionalProperties.toMutableMap() + } + + fun contactId(contactId: String) = contactId(JsonField.of(contactId)) + + /** + * Sets [Builder.contactId] to an arbitrary JSON value. + * + * You should usually call [Builder.contactId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun contactId(contactId: JsonField) = apply { this.contactId = contactId } + + /** The contact's phone number or email */ + fun identifier(identifier: String) = identifier(JsonField.of(identifier)) + + /** + * Sets [Builder.identifier] to an arbitrary JSON value. + * + * You should usually call [Builder.identifier] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun identifier(identifier: JsonField) = apply { this.identifier = identifier } + + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** Alias for calling [Builder.name] with `name.orElse(null)`. */ + fun name(name: Optional) = name(name.getOrNull()) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + 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 [Contact]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Contact = + Contact(contactId, identifier, name, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Contact = apply { + if (validated) { + return@apply + } + + contactId() + identifier() + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (contactId.asKnown().isPresent) 1 else 0) + + (if (identifier.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Contact && + contactId == other.contactId && + identifier == other.identifier && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(contactId, identifier, name, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Contact{contactId=$contactId, identifier=$identifier, name=$name, additionalProperties=$additionalProperties}" + } + + class Direction @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val INBOUND = of("inbound") + + @JvmField val OUTBOUND = of("outbound") + + @JvmStatic fun of(value: String) = Direction(JsonField.of(value)) + } + + /** An enum containing [Direction]'s known values. */ + enum class Known { + INBOUND, + OUTBOUND, + } + + /** + * An enum containing [Direction]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Direction] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + INBOUND, + OUTBOUND, + /** + * An enum member indicating that [Direction] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + INBOUND -> Value.INBOUND + OUTBOUND -> Value.OUTBOUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + INBOUND -> Known.INBOUND + OUTBOUND -> Known.OUTBOUND + else -> throw BlooioInvalidDataException("Unknown Direction: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Direction = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Direction && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class Protocol @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val IMESSAGE = of("imessage") + + @JvmField val SMS = of("sms") + + @JvmField val RCS = of("rcs") + + @JvmField val NON_IMESSAGE = of("non-imessage") + + @JvmStatic fun of(value: String) = Protocol(JsonField.of(value)) + } + + /** An enum containing [Protocol]'s known values. */ + enum class Known { + IMESSAGE, + SMS, + RCS, + NON_IMESSAGE, + } + + /** + * An enum containing [Protocol]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Protocol] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + IMESSAGE, + SMS, + RCS, + NON_IMESSAGE, + /** An enum member indicating that [Protocol] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + IMESSAGE -> Value.IMESSAGE + SMS -> Value.SMS + RCS -> Value.RCS + NON_IMESSAGE -> Value.NON_IMESSAGE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + IMESSAGE -> Known.IMESSAGE + SMS -> Known.SMS + RCS -> Known.RCS + NON_IMESSAGE -> Known.NON_IMESSAGE + else -> throw BlooioInvalidDataException("Unknown Protocol: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Protocol = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Protocol && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val PENDING = of("pending") + + @JvmField val QUEUED = of("queued") + + @JvmField val SENT = of("sent") + + @JvmField val DELIVERED = of("delivered") + + @JvmField val FAILED = of("failed") + + @JvmField val CANCELLATION_REQUESTED = of("cancellation_requested") + + @JvmField val CANCELLED = of("cancelled") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + PENDING, + QUEUED, + SENT, + DELIVERED, + FAILED, + CANCELLATION_REQUESTED, + CANCELLED, + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + PENDING, + QUEUED, + SENT, + DELIVERED, + FAILED, + CANCELLATION_REQUESTED, + CANCELLED, + /** An enum member indicating that [Status] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + PENDING -> Value.PENDING + QUEUED -> Value.QUEUED + SENT -> Value.SENT + DELIVERED -> Value.DELIVERED + FAILED -> Value.FAILED + CANCELLATION_REQUESTED -> Value.CANCELLATION_REQUESTED + CANCELLED -> Value.CANCELLED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + PENDING -> Known.PENDING + QUEUED -> Known.QUEUED + SENT -> Known.SENT + DELIVERED -> Known.DELIVERED + FAILED -> Known.FAILED + CANCELLATION_REQUESTED -> Known.CANCELLATION_REQUESTED + CANCELLED -> Known.CANCELLED + else -> throw BlooioInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Status && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is MessageRetrieveResponse && + attachments == other.attachments && + chatId == other.chatId && + contact == other.contact && + direction == other.direction && + error == other.error && + internalId == other.internalId && + messageId == other.messageId && + protocol == other.protocol && + reactions == other.reactions && + sender == other.sender && + status == other.status && + text == other.text && + timeDelivered == other.timeDelivered && + timeSent == other.timeSent && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + attachments, + chatId, + contact, + direction, + error, + internalId, + messageId, + protocol, + reactions, + sender, + status, + text, + timeDelivered, + timeSent, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "MessageRetrieveResponse{attachments=$attachments, chatId=$chatId, contact=$contact, direction=$direction, error=$error, internalId=$internalId, messageId=$messageId, protocol=$protocol, reactions=$reactions, sender=$sender, status=$status, text=$text, timeDelivered=$timeDelivered, timeSent=$timeSent, additionalProperties=$additionalProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageSendParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageSendParams.kt new file mode 100644 index 0000000..c9c5b51 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageSendParams.kt @@ -0,0 +1,1895 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.messages + +import com.blooio.api.core.BaseDeserializer +import com.blooio.api.core.BaseSerializer +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.core.Params +import com.blooio.api.core.allMaxBy +import com.blooio.api.core.checkKnown +import com.blooio.api.core.checkRequired +import com.blooio.api.core.getOrThrow +import com.blooio.api.core.http.Headers +import com.blooio.api.core.http.QueryParams +import com.blooio.api.core.toImmutable +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Send a message to a chat. The chatId can be: (1) E.164 phone number, (2) email address, (3) group + * ID (grp_xxxx), or (4) comma-separated list of phone/email for multi-recipient chats. For + * multi-recipient, an unnamed group is automatically created or reused if the exact participant + * combination already exists. For explicit groups, the group must be linked to an existing iMessage + * chat. + */ +class MessageSendParams +private constructor( + private val chatId: String?, + private val idempotencyKey: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun chatId(): Optional = Optional.ofNullable(chatId) + + fun idempotencyKey(): Optional = Optional.ofNullable(idempotencyKey) + + /** + * Array of attachment URLs or objects with url/name + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun attachments(): Optional> = body.attachments() + + /** + * E.164 phone number to send from. For Twilio API keys, this is optional — if omitted, the + * first assigned Twilio number is auto-selected. For Blooio (iMessage) API keys, this selects a + * specific number from your pool. Must be a number assigned to your API key. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun fromNumber(): Optional = body.fromNumber() + + /** + * Rich-link-preview overrides for URL messages (iMessage URL balloon). All fields are optional. + * Only applies when the message text (or the concatenated part text) is exactly a single + * http(s) URL. If omitted but the text is a URL, Blooio auto-fetches the page's Open Graph + * metadata to generate a preview. If the image download fails, the send still succeeds — Blooio + * silently falls back to the auto-generated preview. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun linkPreview(): Optional = body.linkPreview() + + /** + * Ordered array of message parts. Two modes: + * 1. **Multipart mode** — parts sent as a single unified iMessage bubble (mix of text and + * attachment parts). This is the default. + * 2. **URL-balloon batch mode** — triggered when any part has a `link_preview` object. Each + * part becomes its own rich-link-preview iMessage; parts are sent sequentially in array + * order. In batch mode every part must be text-only with `text` being a single http(s) URL. + * Response contains `message_ids[]` + `count` instead of `message_id`. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun parts(): Optional> = body.parts() + + /** + * If true, the contact card (Name & Photo) will be shared with this message. The contact card + * is piggybacked onto the outgoing message. Defaults to false. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun shareContact(): Optional = body.shareContact() + + /** + * Message text. Can be a single string or array of strings (each becomes a separate message) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun text(): Optional = body.text() + + /** + * Whether to show typing indicator before sending. Defaults to org preference. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun useTypingIndicator(): Optional = body.useTypingIndicator() + + /** + * Returns the raw JSON value of [attachments]. + * + * Unlike [attachments], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _attachments(): JsonField> = body._attachments() + + /** + * Returns the raw JSON value of [fromNumber]. + * + * Unlike [fromNumber], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _fromNumber(): JsonField = body._fromNumber() + + /** + * Returns the raw JSON value of [linkPreview]. + * + * Unlike [linkPreview], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _linkPreview(): JsonField = body._linkPreview() + + /** + * Returns the raw JSON value of [parts]. + * + * Unlike [parts], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _parts(): JsonField> = body._parts() + + /** + * Returns the raw JSON value of [shareContact]. + * + * Unlike [shareContact], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _shareContact(): JsonField = body._shareContact() + + /** + * Returns the raw JSON value of [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _text(): JsonField = body._text() + + /** + * Returns the raw JSON value of [useTypingIndicator]. + * + * Unlike [useTypingIndicator], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _useTypingIndicator(): JsonField = body._useTypingIndicator() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + /** 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(): MessageSendParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [MessageSendParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [MessageSendParams]. */ + class Builder internal constructor() { + + private var chatId: String? = null + private var idempotencyKey: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(messageSendParams: MessageSendParams) = apply { + chatId = messageSendParams.chatId + idempotencyKey = messageSendParams.idempotencyKey + body = messageSendParams.body.toBuilder() + additionalHeaders = messageSendParams.additionalHeaders.toBuilder() + additionalQueryParams = messageSendParams.additionalQueryParams.toBuilder() + } + + fun chatId(chatId: String?) = apply { this.chatId = chatId } + + /** Alias for calling [Builder.chatId] with `chatId.orElse(null)`. */ + fun chatId(chatId: Optional) = chatId(chatId.getOrNull()) + + fun idempotencyKey(idempotencyKey: String?) = apply { this.idempotencyKey = idempotencyKey } + + /** Alias for calling [Builder.idempotencyKey] with `idempotencyKey.orElse(null)`. */ + fun idempotencyKey(idempotencyKey: Optional) = + idempotencyKey(idempotencyKey.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [attachments] + * - [fromNumber] + * - [linkPreview] + * - [parts] + * - [shareContact] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Array of attachment URLs or objects with url/name */ + fun attachments(attachments: List) = apply { body.attachments(attachments) } + + /** + * Sets [Builder.attachments] to an arbitrary JSON value. + * + * You should usually call [Builder.attachments] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun attachments(attachments: JsonField>) = apply { + body.attachments(attachments) + } + + /** + * Adds a single [Attachment] to [attachments]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAttachment(attachment: Attachment) = apply { body.addAttachment(attachment) } + + /** Alias for calling [addAttachment] with `Attachment.ofString(string)`. */ + fun addAttachment(string: String) = apply { body.addAttachment(string) } + + /** Alias for calling [addAttachment] with `Attachment.ofUnionMember1(unionMember1)`. */ + fun addAttachment(unionMember1: Attachment.UnionMember1) = apply { + body.addAttachment(unionMember1) + } + + /** + * E.164 phone number to send from. For Twilio API keys, this is optional — if omitted, the + * first assigned Twilio number is auto-selected. For Blooio (iMessage) API keys, this + * selects a specific number from your pool. Must be a number assigned to your API key. + */ + fun fromNumber(fromNumber: String) = apply { body.fromNumber(fromNumber) } + + /** + * Sets [Builder.fromNumber] to an arbitrary JSON value. + * + * You should usually call [Builder.fromNumber] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun fromNumber(fromNumber: JsonField) = apply { body.fromNumber(fromNumber) } + + /** + * Rich-link-preview overrides for URL messages (iMessage URL balloon). All fields are + * optional. Only applies when the message text (or the concatenated part text) is exactly a + * single http(s) URL. If omitted but the text is a URL, Blooio auto-fetches the page's Open + * Graph metadata to generate a preview. If the image download fails, the send still + * succeeds — Blooio silently falls back to the auto-generated preview. + */ + fun linkPreview(linkPreview: LinkPreview?) = apply { body.linkPreview(linkPreview) } + + /** Alias for calling [Builder.linkPreview] with `linkPreview.orElse(null)`. */ + fun linkPreview(linkPreview: Optional) = linkPreview(linkPreview.getOrNull()) + + /** + * Sets [Builder.linkPreview] to an arbitrary JSON value. + * + * You should usually call [Builder.linkPreview] with a well-typed [LinkPreview] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun linkPreview(linkPreview: JsonField) = apply { + body.linkPreview(linkPreview) + } + + /** + * Ordered array of message parts. Two modes: + * 1. **Multipart mode** — parts sent as a single unified iMessage bubble (mix of text and + * attachment parts). This is the default. + * 2. **URL-balloon batch mode** — triggered when any part has a `link_preview` object. Each + * part becomes its own rich-link-preview iMessage; parts are sent sequentially in array + * order. In batch mode every part must be text-only with `text` being a single http(s) + * URL. Response contains `message_ids[]` + `count` instead of `message_id`. + */ + fun parts(parts: List) = apply { body.parts(parts) } + + /** + * Sets [Builder.parts] to an arbitrary JSON value. + * + * You should usually call [Builder.parts] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun parts(parts: JsonField>) = apply { body.parts(parts) } + + /** + * Adds a single [Part] to [parts]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addPart(part: Part) = apply { body.addPart(part) } + + /** + * If true, the contact card (Name & Photo) will be shared with this message. The contact + * card is piggybacked onto the outgoing message. Defaults to false. + */ + fun shareContact(shareContact: Boolean) = apply { body.shareContact(shareContact) } + + /** + * Sets [Builder.shareContact] to an arbitrary JSON value. + * + * You should usually call [Builder.shareContact] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun shareContact(shareContact: JsonField) = apply { + body.shareContact(shareContact) + } + + /** + * Message text. Can be a single string or array of strings (each becomes a separate + * message) + */ + fun text(text: Text) = apply { body.text(text) } + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [Text] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun text(text: JsonField) = apply { body.text(text) } + + /** Alias for calling [text] with `Text.ofString(string)`. */ + fun text(string: String) = apply { body.text(string) } + + /** Alias for calling [text] with `Text.ofStrings(strings)`. */ + fun textOfStrings(strings: List) = apply { body.textOfStrings(strings) } + + /** Whether to show typing indicator before sending. Defaults to org preference. */ + fun useTypingIndicator(useTypingIndicator: Boolean) = apply { + body.useTypingIndicator(useTypingIndicator) + } + + /** + * Sets [Builder.useTypingIndicator] to an arbitrary JSON value. + * + * You should usually call [Builder.useTypingIndicator] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun useTypingIndicator(useTypingIndicator: JsonField) = apply { + body.useTypingIndicator(useTypingIndicator) + } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + 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 [MessageSendParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): MessageSendParams = + MessageSendParams( + chatId, + idempotencyKey, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> chatId ?: "" + else -> "" + } + + override fun _headers(): Headers = + Headers.builder() + .apply { + idempotencyKey?.let { put("Idempotency-Key", it) } + putAll(additionalHeaders) + } + .build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + /** Request body for sending a message */ + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val attachments: JsonField>, + private val fromNumber: JsonField, + private val linkPreview: JsonField, + private val parts: JsonField>, + private val shareContact: JsonField, + private val text: JsonField, + private val useTypingIndicator: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("attachments") + @ExcludeMissing + attachments: JsonField> = JsonMissing.of(), + @JsonProperty("from_number") + @ExcludeMissing + fromNumber: JsonField = JsonMissing.of(), + @JsonProperty("link_preview") + @ExcludeMissing + linkPreview: JsonField = JsonMissing.of(), + @JsonProperty("parts") @ExcludeMissing parts: JsonField> = JsonMissing.of(), + @JsonProperty("share_contact") + @ExcludeMissing + shareContact: JsonField = JsonMissing.of(), + @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), + @JsonProperty("use_typing_indicator") + @ExcludeMissing + useTypingIndicator: JsonField = JsonMissing.of(), + ) : this( + attachments, + fromNumber, + linkPreview, + parts, + shareContact, + text, + useTypingIndicator, + mutableMapOf(), + ) + + /** + * Array of attachment URLs or objects with url/name + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun attachments(): Optional> = attachments.getOptional("attachments") + + /** + * E.164 phone number to send from. For Twilio API keys, this is optional — if omitted, the + * first assigned Twilio number is auto-selected. For Blooio (iMessage) API keys, this + * selects a specific number from your pool. Must be a number assigned to your API key. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun fromNumber(): Optional = fromNumber.getOptional("from_number") + + /** + * Rich-link-preview overrides for URL messages (iMessage URL balloon). All fields are + * optional. Only applies when the message text (or the concatenated part text) is exactly a + * single http(s) URL. If omitted but the text is a URL, Blooio auto-fetches the page's Open + * Graph metadata to generate a preview. If the image download fails, the send still + * succeeds — Blooio silently falls back to the auto-generated preview. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun linkPreview(): Optional = linkPreview.getOptional("link_preview") + + /** + * Ordered array of message parts. Two modes: + * 1. **Multipart mode** — parts sent as a single unified iMessage bubble (mix of text and + * attachment parts). This is the default. + * 2. **URL-balloon batch mode** — triggered when any part has a `link_preview` object. Each + * part becomes its own rich-link-preview iMessage; parts are sent sequentially in array + * order. In batch mode every part must be text-only with `text` being a single http(s) + * URL. Response contains `message_ids[]` + `count` instead of `message_id`. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun parts(): Optional> = parts.getOptional("parts") + + /** + * If true, the contact card (Name & Photo) will be shared with this message. The contact + * card is piggybacked onto the outgoing message. Defaults to false. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun shareContact(): Optional = shareContact.getOptional("share_contact") + + /** + * Message text. Can be a single string or array of strings (each becomes a separate + * message) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun text(): Optional = text.getOptional("text") + + /** + * Whether to show typing indicator before sending. Defaults to org preference. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun useTypingIndicator(): Optional = + useTypingIndicator.getOptional("use_typing_indicator") + + /** + * Returns the raw JSON value of [attachments]. + * + * Unlike [attachments], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("attachments") + @ExcludeMissing + fun _attachments(): JsonField> = attachments + + /** + * Returns the raw JSON value of [fromNumber]. + * + * Unlike [fromNumber], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("from_number") + @ExcludeMissing + fun _fromNumber(): JsonField = fromNumber + + /** + * Returns the raw JSON value of [linkPreview]. + * + * Unlike [linkPreview], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("link_preview") + @ExcludeMissing + fun _linkPreview(): JsonField = linkPreview + + /** + * Returns the raw JSON value of [parts]. + * + * Unlike [parts], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("parts") @ExcludeMissing fun _parts(): JsonField> = parts + + /** + * Returns the raw JSON value of [shareContact]. + * + * Unlike [shareContact], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("share_contact") + @ExcludeMissing + fun _shareContact(): JsonField = shareContact + + /** + * Returns the raw JSON value of [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text + + /** + * Returns the raw JSON value of [useTypingIndicator]. + * + * Unlike [useTypingIndicator], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("use_typing_indicator") + @ExcludeMissing + fun _useTypingIndicator(): JsonField = useTypingIndicator + + @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 [Body]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var attachments: JsonField>? = null + private var fromNumber: JsonField = JsonMissing.of() + private var linkPreview: JsonField = JsonMissing.of() + private var parts: JsonField>? = null + private var shareContact: JsonField = JsonMissing.of() + private var text: JsonField = JsonMissing.of() + private var useTypingIndicator: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + attachments = body.attachments.map { it.toMutableList() } + fromNumber = body.fromNumber + linkPreview = body.linkPreview + parts = body.parts.map { it.toMutableList() } + shareContact = body.shareContact + text = body.text + useTypingIndicator = body.useTypingIndicator + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Array of attachment URLs or objects with url/name */ + fun attachments(attachments: List) = attachments(JsonField.of(attachments)) + + /** + * Sets [Builder.attachments] to an arbitrary JSON value. + * + * You should usually call [Builder.attachments] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun attachments(attachments: JsonField>) = apply { + this.attachments = attachments.map { it.toMutableList() } + } + + /** + * Adds a single [Attachment] to [attachments]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAttachment(attachment: Attachment) = apply { + attachments = + (attachments ?: JsonField.of(mutableListOf())).also { + checkKnown("attachments", it).add(attachment) + } + } + + /** Alias for calling [addAttachment] with `Attachment.ofString(string)`. */ + fun addAttachment(string: String) = addAttachment(Attachment.ofString(string)) + + /** Alias for calling [addAttachment] with `Attachment.ofUnionMember1(unionMember1)`. */ + fun addAttachment(unionMember1: Attachment.UnionMember1) = + addAttachment(Attachment.ofUnionMember1(unionMember1)) + + /** + * E.164 phone number to send from. For Twilio API keys, this is optional — if omitted, + * the first assigned Twilio number is auto-selected. For Blooio (iMessage) API keys, + * this selects a specific number from your pool. Must be a number assigned to your API + * key. + */ + fun fromNumber(fromNumber: String) = fromNumber(JsonField.of(fromNumber)) + + /** + * Sets [Builder.fromNumber] to an arbitrary JSON value. + * + * You should usually call [Builder.fromNumber] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun fromNumber(fromNumber: JsonField) = apply { this.fromNumber = fromNumber } + + /** + * Rich-link-preview overrides for URL messages (iMessage URL balloon). All fields are + * optional. Only applies when the message text (or the concatenated part text) is + * exactly a single http(s) URL. If omitted but the text is a URL, Blooio auto-fetches + * the page's Open Graph metadata to generate a preview. If the image download fails, + * the send still succeeds — Blooio silently falls back to the auto-generated preview. + */ + fun linkPreview(linkPreview: LinkPreview?) = + linkPreview(JsonField.ofNullable(linkPreview)) + + /** Alias for calling [Builder.linkPreview] with `linkPreview.orElse(null)`. */ + fun linkPreview(linkPreview: Optional) = + linkPreview(linkPreview.getOrNull()) + + /** + * Sets [Builder.linkPreview] to an arbitrary JSON value. + * + * You should usually call [Builder.linkPreview] with a well-typed [LinkPreview] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun linkPreview(linkPreview: JsonField) = apply { + this.linkPreview = linkPreview + } + + /** + * Ordered array of message parts. Two modes: + * 1. **Multipart mode** — parts sent as a single unified iMessage bubble (mix of text + * and attachment parts). This is the default. + * 2. **URL-balloon batch mode** — triggered when any part has a `link_preview` object. + * Each part becomes its own rich-link-preview iMessage; parts are sent sequentially + * in array order. In batch mode every part must be text-only with `text` being a + * single http(s) URL. Response contains `message_ids[]` + `count` instead of + * `message_id`. + */ + fun parts(parts: List) = parts(JsonField.of(parts)) + + /** + * Sets [Builder.parts] to an arbitrary JSON value. + * + * You should usually call [Builder.parts] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun parts(parts: JsonField>) = apply { + this.parts = parts.map { it.toMutableList() } + } + + /** + * Adds a single [Part] to [parts]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addPart(part: Part) = apply { + parts = + (parts ?: JsonField.of(mutableListOf())).also { + checkKnown("parts", it).add(part) + } + } + + /** + * If true, the contact card (Name & Photo) will be shared with this message. The + * contact card is piggybacked onto the outgoing message. Defaults to false. + */ + fun shareContact(shareContact: Boolean) = shareContact(JsonField.of(shareContact)) + + /** + * Sets [Builder.shareContact] to an arbitrary JSON value. + * + * You should usually call [Builder.shareContact] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun shareContact(shareContact: JsonField) = apply { + this.shareContact = shareContact + } + + /** + * Message text. Can be a single string or array of strings (each becomes a separate + * message) + */ + fun text(text: Text) = text(JsonField.of(text)) + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [Text] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun text(text: JsonField) = apply { this.text = text } + + /** Alias for calling [text] with `Text.ofString(string)`. */ + fun text(string: String) = text(Text.ofString(string)) + + /** Alias for calling [text] with `Text.ofStrings(strings)`. */ + fun textOfStrings(strings: List) = text(Text.ofStrings(strings)) + + /** Whether to show typing indicator before sending. Defaults to org preference. */ + fun useTypingIndicator(useTypingIndicator: Boolean) = + useTypingIndicator(JsonField.of(useTypingIndicator)) + + /** + * Sets [Builder.useTypingIndicator] to an arbitrary JSON value. + * + * You should usually call [Builder.useTypingIndicator] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun useTypingIndicator(useTypingIndicator: JsonField) = apply { + this.useTypingIndicator = useTypingIndicator + } + + 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 [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = + Body( + (attachments ?: JsonMissing.of()).map { it.toImmutable() }, + fromNumber, + linkPreview, + (parts ?: JsonMissing.of()).map { it.toImmutable() }, + shareContact, + text, + useTypingIndicator, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + attachments().ifPresent { it.forEach { it.validate() } } + fromNumber() + linkPreview().ifPresent { it.validate() } + parts().ifPresent { it.forEach { it.validate() } } + shareContact() + text().ifPresent { it.validate() } + useTypingIndicator() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 = + (attachments.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (fromNumber.asKnown().isPresent) 1 else 0) + + (linkPreview.asKnown().getOrNull()?.validity() ?: 0) + + (parts.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (shareContact.asKnown().isPresent) 1 else 0) + + (text.asKnown().getOrNull()?.validity() ?: 0) + + (if (useTypingIndicator.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + attachments == other.attachments && + fromNumber == other.fromNumber && + linkPreview == other.linkPreview && + parts == other.parts && + shareContact == other.shareContact && + text == other.text && + useTypingIndicator == other.useTypingIndicator && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + attachments, + fromNumber, + linkPreview, + parts, + shareContact, + text, + useTypingIndicator, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{attachments=$attachments, fromNumber=$fromNumber, linkPreview=$linkPreview, parts=$parts, shareContact=$shareContact, text=$text, useTypingIndicator=$useTypingIndicator, additionalProperties=$additionalProperties}" + } + + /** URL to the attachment */ + @JsonDeserialize(using = Attachment.Deserializer::class) + @JsonSerialize(using = Attachment.Serializer::class) + class Attachment + private constructor( + private val string: String? = null, + private val unionMember1: UnionMember1? = null, + private val _json: JsonValue? = null, + ) { + + /** URL to the attachment */ + fun string(): Optional = Optional.ofNullable(string) + + fun unionMember1(): Optional = Optional.ofNullable(unionMember1) + + fun isString(): Boolean = string != null + + fun isUnionMember1(): Boolean = unionMember1 != null + + /** URL to the attachment */ + fun asString(): String = string.getOrThrow("string") + + fun asUnionMember1(): UnionMember1 = unionMember1.getOrThrow("unionMember1") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + string != null -> visitor.visitString(string) + unionMember1 != null -> visitor.visitUnionMember1(unionMember1) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Attachment = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitString(string: String) {} + + override fun visitUnionMember1(unionMember1: UnionMember1) { + unionMember1.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 = + accept( + object : Visitor { + override fun visitString(string: String) = 1 + + override fun visitUnionMember1(unionMember1: UnionMember1) = + unionMember1.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Attachment && + string == other.string && + unionMember1 == other.unionMember1 + } + + override fun hashCode(): Int = Objects.hash(string, unionMember1) + + override fun toString(): String = + when { + string != null -> "Attachment{string=$string}" + unionMember1 != null -> "Attachment{unionMember1=$unionMember1}" + _json != null -> "Attachment{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Attachment") + } + + companion object { + + /** URL to the attachment */ + @JvmStatic fun ofString(string: String) = Attachment(string = string) + + @JvmStatic + fun ofUnionMember1(unionMember1: UnionMember1) = Attachment(unionMember1 = unionMember1) + } + + /** + * An interface that defines how to map each variant of [Attachment] to a value of type [T]. + */ + interface Visitor { + + /** URL to the attachment */ + fun visitString(string: String): T + + fun visitUnionMember1(unionMember1: UnionMember1): T + + /** + * Maps an unknown variant of [Attachment] to a value of type [T]. + * + * An instance of [Attachment] can contain an unknown variant if it was deserialized + * from data that doesn't match any known variant. For example, if the SDK is on an + * older version than the API, then the API may respond with new variants that the SDK + * is unaware of. + * + * @throws BlooioInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw BlooioInvalidDataException("Unknown Attachment: $json") + } + } + + internal class Deserializer : BaseDeserializer(Attachment::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Attachment { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Attachment(unionMember1 = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Attachment(string = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> Attachment(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Attachment::class) { + + override fun serialize( + value: Attachment, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.string != null -> generator.writeObject(value.string) + value.unionMember1 != null -> generator.writeObject(value.unionMember1) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Attachment") + } + } + } + + class UnionMember1 + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val url: JsonField, + private val name: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(url, name, mutableMapOf()) + + /** + * @throws BlooioInvalidDataException 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 url(): String = url.getRequired("url") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + @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 [UnionMember1]. + * + * The following fields are required: + * ```java + * .url() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [UnionMember1]. */ + class Builder internal constructor() { + + private var url: JsonField? = null + private var name: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(unionMember1: UnionMember1) = apply { + url = unionMember1.url + name = unionMember1.name + additionalProperties = unionMember1.additionalProperties.toMutableMap() + } + + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + 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 [UnionMember1]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): UnionMember1 = + UnionMember1( + checkRequired("url", url), + name, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): UnionMember1 = apply { + if (validated) { + return@apply + } + + url() + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (url.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is UnionMember1 && + url == other.url && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(url, name, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "UnionMember1{url=$url, name=$name, additionalProperties=$additionalProperties}" + } + } + + class Part + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val linkPreview: JsonField, + private val mention: JsonField, + private val name: JsonField, + private val text: JsonField, + private val url: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("link_preview") + @ExcludeMissing + linkPreview: JsonField = JsonMissing.of(), + @JsonProperty("mention") @ExcludeMissing mention: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this(linkPreview, mention, name, text, url, mutableMapOf()) + + /** + * Rich-link-preview overrides for URL messages (iMessage URL balloon). All fields are + * optional. Only applies when the message text (or the concatenated part text) is exactly a + * single http(s) URL. If omitted but the text is a URL, Blooio auto-fetches the page's Open + * Graph metadata to generate a preview. If the image download fails, the send still + * succeeds — Blooio silently falls back to the auto-generated preview. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun linkPreview(): Optional = linkPreview.getOptional("link_preview") + + /** + * Participant phone number or email to @-mention. Only valid with 'text'. The entire text + * of the part is rendered as the mention. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun mention(): Optional = mention.getOptional("mention") + + /** + * Filename for the attachment. Only valid with 'url'. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * Text content for this part. Mutually exclusive with 'url'. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun text(): Optional = text.getOptional("text") + + /** + * URL to an attachment for this part. Mutually exclusive with 'text'. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun url(): Optional = url.getOptional("url") + + /** + * Returns the raw JSON value of [linkPreview]. + * + * Unlike [linkPreview], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("link_preview") + @ExcludeMissing + fun _linkPreview(): JsonField = linkPreview + + /** + * Returns the raw JSON value of [mention]. + * + * Unlike [mention], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("mention") @ExcludeMissing fun _mention(): JsonField = mention + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + @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 [Part]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Part]. */ + class Builder internal constructor() { + + private var linkPreview: JsonField = JsonMissing.of() + private var mention: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var text: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(part: Part) = apply { + linkPreview = part.linkPreview + mention = part.mention + name = part.name + text = part.text + url = part.url + additionalProperties = part.additionalProperties.toMutableMap() + } + + /** + * Rich-link-preview overrides for URL messages (iMessage URL balloon). All fields are + * optional. Only applies when the message text (or the concatenated part text) is + * exactly a single http(s) URL. If omitted but the text is a URL, Blooio auto-fetches + * the page's Open Graph metadata to generate a preview. If the image download fails, + * the send still succeeds — Blooio silently falls back to the auto-generated preview. + */ + fun linkPreview(linkPreview: LinkPreview?) = + linkPreview(JsonField.ofNullable(linkPreview)) + + /** Alias for calling [Builder.linkPreview] with `linkPreview.orElse(null)`. */ + fun linkPreview(linkPreview: Optional) = + linkPreview(linkPreview.getOrNull()) + + /** + * Sets [Builder.linkPreview] to an arbitrary JSON value. + * + * You should usually call [Builder.linkPreview] with a well-typed [LinkPreview] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun linkPreview(linkPreview: JsonField) = apply { + this.linkPreview = linkPreview + } + + /** + * Participant phone number or email to @-mention. Only valid with 'text'. The entire + * text of the part is rendered as the mention. + */ + fun mention(mention: String) = mention(JsonField.of(mention)) + + /** + * Sets [Builder.mention] to an arbitrary JSON value. + * + * You should usually call [Builder.mention] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun mention(mention: JsonField) = apply { this.mention = mention } + + /** Filename for the attachment. Only valid with 'url'. */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Text content for this part. Mutually exclusive with 'url'. */ + fun text(text: String) = text(JsonField.of(text)) + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun text(text: JsonField) = apply { this.text = text } + + /** URL to an attachment for this part. Mutually exclusive with 'text'. */ + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + + 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 [Part]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Part = + Part(linkPreview, mention, name, text, url, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Part = apply { + if (validated) { + return@apply + } + + linkPreview().ifPresent { it.validate() } + mention() + name() + text() + url() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 = + (linkPreview.asKnown().getOrNull()?.validity() ?: 0) + + (if (mention.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (text.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Part && + linkPreview == other.linkPreview && + mention == other.mention && + name == other.name && + text == other.text && + url == other.url && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(linkPreview, mention, name, text, url, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Part{linkPreview=$linkPreview, mention=$mention, name=$name, text=$text, url=$url, additionalProperties=$additionalProperties}" + } + + /** + * Message text. Can be a single string or array of strings (each becomes a separate message) + */ + @JsonDeserialize(using = Text.Deserializer::class) + @JsonSerialize(using = Text.Serializer::class) + class Text + private constructor( + private val string: String? = null, + private val strings: List? = null, + private val _json: JsonValue? = null, + ) { + + fun string(): Optional = Optional.ofNullable(string) + + fun strings(): Optional> = Optional.ofNullable(strings) + + fun isString(): Boolean = string != null + + fun isStrings(): Boolean = strings != null + + fun asString(): String = string.getOrThrow("string") + + fun asStrings(): List = strings.getOrThrow("strings") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + string != null -> visitor.visitString(string) + strings != null -> visitor.visitStrings(strings) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Text = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitString(string: String) {} + + override fun visitStrings(strings: List) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 = + accept( + object : Visitor { + override fun visitString(string: String) = 1 + + override fun visitStrings(strings: List) = strings.size + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Text && string == other.string && strings == other.strings + } + + override fun hashCode(): Int = Objects.hash(string, strings) + + override fun toString(): String = + when { + string != null -> "Text{string=$string}" + strings != null -> "Text{strings=$strings}" + _json != null -> "Text{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Text") + } + + companion object { + + @JvmStatic fun ofString(string: String) = Text(string = string) + + @JvmStatic fun ofStrings(strings: List) = Text(strings = strings.toImmutable()) + } + + /** An interface that defines how to map each variant of [Text] to a value of type [T]. */ + interface Visitor { + + fun visitString(string: String): T + + fun visitStrings(strings: List): T + + /** + * Maps an unknown variant of [Text] to a value of type [T]. + * + * An instance of [Text] can contain an unknown variant if it was deserialized from data + * that doesn't match any known variant. For example, if the SDK is on an older version + * than the API, then the API may respond with new variants that the SDK is unaware of. + * + * @throws BlooioInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw BlooioInvalidDataException("Unknown Text: $json") + } + } + + internal class Deserializer : BaseDeserializer(Text::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Text { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Text(string = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef>())?.let { + Text(strings = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> Text(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Text::class) { + + override fun serialize( + value: Text, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.string != null -> generator.writeObject(value.string) + value.strings != null -> generator.writeObject(value.strings) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Text") + } + } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is MessageSendParams && + chatId == other.chatId && + idempotencyKey == other.idempotencyKey && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(chatId, idempotencyKey, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "MessageSendParams{chatId=$chatId, idempotencyKey=$idempotencyKey, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageSendResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageSendResponse.kt new file mode 100644 index 0000000..ad427b2 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/MessageSendResponse.kt @@ -0,0 +1,566 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.messages + +import com.blooio.api.core.Enum +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.core.checkKnown +import com.blooio.api.core.toImmutable +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Response after sending a message */ +class MessageSendResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val count: JsonField, + private val groupCreated: JsonField, + private val groupId: JsonField, + private val messageId: JsonField, + private val messageIds: JsonField>, + private val participants: JsonField>, + private val status: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("count") @ExcludeMissing count: JsonField = JsonMissing.of(), + @JsonProperty("group_created") + @ExcludeMissing + groupCreated: JsonField = JsonMissing.of(), + @JsonProperty("group_id") @ExcludeMissing groupId: JsonField = JsonMissing.of(), + @JsonProperty("message_id") @ExcludeMissing messageId: JsonField = JsonMissing.of(), + @JsonProperty("message_ids") + @ExcludeMissing + messageIds: JsonField> = JsonMissing.of(), + @JsonProperty("participants") + @ExcludeMissing + participants: JsonField> = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + ) : this( + count, + groupCreated, + groupId, + messageId, + messageIds, + participants, + status, + mutableMapOf(), + ) + + /** + * Number of messages sent. Only present in URL-balloon batch mode. + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun count(): Optional = count.getOptional("count") + + /** + * True if a new unnamed group was created for this multi-recipient message + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun groupCreated(): Optional = groupCreated.getOptional("group_created") + + /** + * Group ID when sending to multi-recipient (new or existing) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun groupId(): Optional = groupId.getOptional("group_id") + + /** + * ID of the sent message (single-message sends) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun messageId(): Optional = messageId.getOptional("message_id") + + /** + * IDs of sent messages. Present when `text` is an array or when `parts` uses per-part + * `link_preview` (URL-balloon batch mode). + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun messageIds(): Optional> = messageIds.getOptional("message_ids") + + /** + * List of participants (present for multi-recipient) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun participants(): Optional> = participants.getOptional("participants") + + /** + * Initial status of the message(s) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun status(): Optional = status.getOptional("status") + + /** + * Returns the raw JSON value of [count]. + * + * Unlike [count], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("count") @ExcludeMissing fun _count(): JsonField = count + + /** + * Returns the raw JSON value of [groupCreated]. + * + * Unlike [groupCreated], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_created") + @ExcludeMissing + fun _groupCreated(): JsonField = groupCreated + + /** + * Returns the raw JSON value of [groupId]. + * + * Unlike [groupId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_id") @ExcludeMissing fun _groupId(): JsonField = groupId + + /** + * Returns the raw JSON value of [messageId]. + * + * Unlike [messageId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message_id") @ExcludeMissing fun _messageId(): JsonField = messageId + + /** + * Returns the raw JSON value of [messageIds]. + * + * Unlike [messageIds], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message_ids") + @ExcludeMissing + fun _messageIds(): JsonField> = messageIds + + /** + * Returns the raw JSON value of [participants]. + * + * Unlike [participants], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("participants") + @ExcludeMissing + fun _participants(): JsonField> = participants + + /** + * Returns the raw JSON value of [status]. + * + * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + + @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 [MessageSendResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [MessageSendResponse]. */ + class Builder internal constructor() { + + private var count: JsonField = JsonMissing.of() + private var groupCreated: JsonField = JsonMissing.of() + private var groupId: JsonField = JsonMissing.of() + private var messageId: JsonField = JsonMissing.of() + private var messageIds: JsonField>? = null + private var participants: JsonField>? = null + private var status: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(messageSendResponse: MessageSendResponse) = apply { + count = messageSendResponse.count + groupCreated = messageSendResponse.groupCreated + groupId = messageSendResponse.groupId + messageId = messageSendResponse.messageId + messageIds = messageSendResponse.messageIds.map { it.toMutableList() } + participants = messageSendResponse.participants.map { it.toMutableList() } + status = messageSendResponse.status + additionalProperties = messageSendResponse.additionalProperties.toMutableMap() + } + + /** Number of messages sent. Only present in URL-balloon batch mode. */ + fun count(count: Long) = count(JsonField.of(count)) + + /** + * Sets [Builder.count] to an arbitrary JSON value. + * + * You should usually call [Builder.count] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun count(count: JsonField) = apply { this.count = count } + + /** True if a new unnamed group was created for this multi-recipient message */ + fun groupCreated(groupCreated: Boolean) = groupCreated(JsonField.of(groupCreated)) + + /** + * Sets [Builder.groupCreated] to an arbitrary JSON value. + * + * You should usually call [Builder.groupCreated] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun groupCreated(groupCreated: JsonField) = apply { + this.groupCreated = groupCreated + } + + /** Group ID when sending to multi-recipient (new or existing) */ + fun groupId(groupId: String) = groupId(JsonField.of(groupId)) + + /** + * Sets [Builder.groupId] to an arbitrary JSON value. + * + * You should usually call [Builder.groupId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun groupId(groupId: JsonField) = apply { this.groupId = groupId } + + /** ID of the sent message (single-message sends) */ + fun messageId(messageId: String) = messageId(JsonField.of(messageId)) + + /** + * Sets [Builder.messageId] to an arbitrary JSON value. + * + * You should usually call [Builder.messageId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun messageId(messageId: JsonField) = apply { this.messageId = messageId } + + /** + * IDs of sent messages. Present when `text` is an array or when `parts` uses per-part + * `link_preview` (URL-balloon batch mode). + */ + fun messageIds(messageIds: List) = messageIds(JsonField.of(messageIds)) + + /** + * Sets [Builder.messageIds] to an arbitrary JSON value. + * + * You should usually call [Builder.messageIds] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun messageIds(messageIds: JsonField>) = apply { + this.messageIds = messageIds.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [messageIds]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMessageId(messageId: String) = apply { + messageIds = + (messageIds ?: JsonField.of(mutableListOf())).also { + checkKnown("messageIds", it).add(messageId) + } + } + + /** List of participants (present for multi-recipient) */ + fun participants(participants: List) = participants(JsonField.of(participants)) + + /** + * Sets [Builder.participants] to an arbitrary JSON value. + * + * You should usually call [Builder.participants] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun participants(participants: JsonField>) = apply { + this.participants = participants.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [participants]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addParticipant(participant: String) = apply { + participants = + (participants ?: JsonField.of(mutableListOf())).also { + checkKnown("participants", it).add(participant) + } + } + + /** Initial status of the message(s) */ + fun status(status: Status) = status(JsonField.of(status)) + + /** + * Sets [Builder.status] to an arbitrary JSON value. + * + * You should usually call [Builder.status] with a well-typed [Status] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun status(status: JsonField) = apply { this.status = status } + + 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 [MessageSendResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): MessageSendResponse = + MessageSendResponse( + count, + groupCreated, + groupId, + messageId, + (messageIds ?: JsonMissing.of()).map { it.toImmutable() }, + (participants ?: JsonMissing.of()).map { it.toImmutable() }, + status, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): MessageSendResponse = apply { + if (validated) { + return@apply + } + + count() + groupCreated() + groupId() + messageId() + messageIds() + participants() + status().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (count.asKnown().isPresent) 1 else 0) + + (if (groupCreated.asKnown().isPresent) 1 else 0) + + (if (groupId.asKnown().isPresent) 1 else 0) + + (if (messageId.asKnown().isPresent) 1 else 0) + + (messageIds.asKnown().getOrNull()?.size ?: 0) + + (participants.asKnown().getOrNull()?.size ?: 0) + + (status.asKnown().getOrNull()?.validity() ?: 0) + + /** Initial status of the message(s) */ + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val QUEUED = of("queued") + + @JvmField val FAILED = of("failed") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + QUEUED, + FAILED, + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + QUEUED, + FAILED, + /** An enum member indicating that [Status] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + QUEUED -> Value.QUEUED + FAILED -> Value.FAILED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws BlooioInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + QUEUED -> Known.QUEUED + FAILED -> Known.FAILED + else -> throw BlooioInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws BlooioInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { BlooioInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Status && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is MessageSendResponse && + count == other.count && + groupCreated == other.groupCreated && + groupId == other.groupId && + messageId == other.messageId && + messageIds == other.messageIds && + participants == other.participants && + status == other.status && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + count, + groupCreated, + groupId, + messageId, + messageIds, + participants, + status, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "MessageSendResponse{count=$count, groupCreated=$groupCreated, groupId=$groupId, messageId=$messageId, messageIds=$messageIds, participants=$participants, status=$status, additionalProperties=$additionalProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/Reaction.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/Reaction.kt new file mode 100644 index 0000000..a63dd51 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/messages/Reaction.kt @@ -0,0 +1,271 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.messages + +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class Reaction +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val isAdded: JsonField, + private val reaction: JsonField, + private val sender: JsonField, + private val timeSent: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("is_added") @ExcludeMissing isAdded: JsonField = JsonMissing.of(), + @JsonProperty("reaction") @ExcludeMissing reaction: JsonField = JsonMissing.of(), + @JsonProperty("sender") @ExcludeMissing sender: JsonField = JsonMissing.of(), + @JsonProperty("time_sent") @ExcludeMissing timeSent: JsonField = JsonMissing.of(), + ) : this(isAdded, reaction, sender, timeSent, mutableMapOf()) + + /** + * Whether the reaction is currently active (true) or was removed (false) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun isAdded(): Optional = isAdded.getOptional("is_added") + + /** + * The reaction value. Classic tapbacks: love, like, dislike, laugh, emphasize, question. Emoji + * reactions: the emoji character (e.g. 😂, 👍). + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun reaction(): Optional = reaction.getOptional("reaction") + + /** + * Phone number or email of who sent the reaction. Null when the reaction was sent by you + * (outbound). + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun sender(): Optional = sender.getOptional("sender") + + /** + * Timestamp when the reaction was sent (ms) + * + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun timeSent(): Optional = timeSent.getOptional("time_sent") + + /** + * Returns the raw JSON value of [isAdded]. + * + * Unlike [isAdded], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("is_added") @ExcludeMissing fun _isAdded(): JsonField = isAdded + + /** + * Returns the raw JSON value of [reaction]. + * + * Unlike [reaction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("reaction") @ExcludeMissing fun _reaction(): JsonField = reaction + + /** + * Returns the raw JSON value of [sender]. + * + * Unlike [sender], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("sender") @ExcludeMissing fun _sender(): JsonField = sender + + /** + * Returns the raw JSON value of [timeSent]. + * + * Unlike [timeSent], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("time_sent") @ExcludeMissing fun _timeSent(): JsonField = timeSent + + @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 [Reaction]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Reaction]. */ + class Builder internal constructor() { + + private var isAdded: JsonField = JsonMissing.of() + private var reaction: JsonField = JsonMissing.of() + private var sender: JsonField = JsonMissing.of() + private var timeSent: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(reaction: Reaction) = apply { + isAdded = reaction.isAdded + this.reaction = reaction.reaction + sender = reaction.sender + timeSent = reaction.timeSent + additionalProperties = reaction.additionalProperties.toMutableMap() + } + + /** Whether the reaction is currently active (true) or was removed (false) */ + fun isAdded(isAdded: Boolean) = isAdded(JsonField.of(isAdded)) + + /** + * Sets [Builder.isAdded] to an arbitrary JSON value. + * + * You should usually call [Builder.isAdded] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun isAdded(isAdded: JsonField) = apply { this.isAdded = isAdded } + + /** + * The reaction value. Classic tapbacks: love, like, dislike, laugh, emphasize, question. + * Emoji reactions: the emoji character (e.g. 😂, 👍). + */ + fun reaction(reaction: String) = reaction(JsonField.of(reaction)) + + /** + * Sets [Builder.reaction] to an arbitrary JSON value. + * + * You should usually call [Builder.reaction] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun reaction(reaction: JsonField) = apply { this.reaction = reaction } + + /** + * Phone number or email of who sent the reaction. Null when the reaction was sent by you + * (outbound). + */ + fun sender(sender: String?) = sender(JsonField.ofNullable(sender)) + + /** Alias for calling [Builder.sender] with `sender.orElse(null)`. */ + fun sender(sender: Optional) = sender(sender.getOrNull()) + + /** + * Sets [Builder.sender] to an arbitrary JSON value. + * + * You should usually call [Builder.sender] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun sender(sender: JsonField) = apply { this.sender = sender } + + /** Timestamp when the reaction was sent (ms) */ + fun timeSent(timeSent: Long) = timeSent(JsonField.of(timeSent)) + + /** + * Sets [Builder.timeSent] to an arbitrary JSON value. + * + * You should usually call [Builder.timeSent] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun timeSent(timeSent: JsonField) = apply { this.timeSent = timeSent } + + 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 [Reaction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Reaction = + Reaction(isAdded, reaction, sender, timeSent, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Reaction = apply { + if (validated) { + return@apply + } + + isAdded() + reaction() + sender() + timeSent() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BlooioInvalidDataException) { + 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 (isAdded.asKnown().isPresent) 1 else 0) + + (if (reaction.asKnown().isPresent) 1 else 0) + + (if (sender.asKnown().isPresent) 1 else 0) + + (if (timeSent.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Reaction && + isAdded == other.isAdded && + reaction == other.reaction && + sender == other.sender && + timeSent == other.timeSent && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(isAdded, reaction, sender, timeSent, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Reaction{isAdded=$isAdded, reaction=$reaction, sender=$sender, timeSent=$timeSent, additionalProperties=$additionalProperties}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/polls/PollGetResultsParams.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/polls/PollGetResultsParams.kt new file mode 100644 index 0000000..b15a832 --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/polls/PollGetResultsParams.kt @@ -0,0 +1,220 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.polls + +import com.blooio.api.core.Params +import com.blooio.api.core.checkRequired +import com.blooio.api.core.http.Headers +import com.blooio.api.core.http.QueryParams +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Retrieve a poll's definition and aggregated vote counts. The pollId is the poll_id returned in + * the poll.received or poll.created webhook event. + */ +class PollGetResultsParams +private constructor( + private val chatId: String, + private val pollId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun chatId(): String = chatId + + fun pollId(): Optional = Optional.ofNullable(pollId) + + /** 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 [PollGetResultsParams]. + * + * The following fields are required: + * ```java + * .chatId() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PollGetResultsParams]. */ + class Builder internal constructor() { + + private var chatId: String? = null + private var pollId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(pollGetResultsParams: PollGetResultsParams) = apply { + chatId = pollGetResultsParams.chatId + pollId = pollGetResultsParams.pollId + additionalHeaders = pollGetResultsParams.additionalHeaders.toBuilder() + additionalQueryParams = pollGetResultsParams.additionalQueryParams.toBuilder() + } + + fun chatId(chatId: String) = apply { this.chatId = chatId } + + fun pollId(pollId: String?) = apply { this.pollId = pollId } + + /** Alias for calling [Builder.pollId] with `pollId.orElse(null)`. */ + fun pollId(pollId: Optional) = pollId(pollId.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) + } + + /** + * Returns an immutable instance of [PollGetResultsParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .chatId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PollGetResultsParams = + PollGetResultsParams( + checkRequired("chatId", chatId), + pollId, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> chatId + 1 -> pollId ?: "" + 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 PollGetResultsParams && + chatId == other.chatId && + pollId == other.pollId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(chatId, pollId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "PollGetResultsParams{chatId=$chatId, pollId=$pollId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/polls/PollGetResultsResponse.kt b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/polls/PollGetResultsResponse.kt new file mode 100644 index 0000000..e9d889f --- /dev/null +++ b/blooio-java-core/src/main/kotlin/com/blooio/api/models/chats/polls/PollGetResultsResponse.kt @@ -0,0 +1,474 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.blooio.api.models.chats.polls + +import com.blooio.api.core.ExcludeMissing +import com.blooio.api.core.JsonField +import com.blooio.api.core.JsonMissing +import com.blooio.api.core.JsonValue +import com.blooio.api.core.checkKnown +import com.blooio.api.core.toImmutable +import com.blooio.api.errors.BlooioInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class PollGetResultsResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val chatId: JsonField, + private val options: JsonField>, + private val pollId: JsonField, + private val title: JsonField, + private val totalVotes: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("chat_id") @ExcludeMissing chatId: JsonField = JsonMissing.of(), + @JsonProperty("options") + @ExcludeMissing + options: JsonField> = JsonMissing.of(), + @JsonProperty("poll_id") @ExcludeMissing pollId: JsonField = JsonMissing.of(), + @JsonProperty("title") @ExcludeMissing title: JsonField = JsonMissing.of(), + @JsonProperty("total_votes") @ExcludeMissing totalVotes: JsonField = JsonMissing.of(), + ) : this(chatId, options, pollId, title, totalVotes, mutableMapOf()) + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun chatId(): Optional = chatId.getOptional("chat_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): Optional> = options.getOptional("options") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun pollId(): Optional = pollId.getOptional("poll_id") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun title(): Optional = title.getOptional("title") + + /** + * @throws BlooioInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun totalVotes(): Optional = totalVotes.getOptional("total_votes") + + /** + * Returns the raw JSON value of [chatId]. + * + * Unlike [chatId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("chat_id") @ExcludeMissing fun _chatId(): JsonField = chatId + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("options") @ExcludeMissing fun _options(): JsonField> = options + + /** + * Returns the raw JSON value of [pollId]. + * + * Unlike [pollId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("poll_id") @ExcludeMissing fun _pollId(): JsonField = pollId + + /** + * Returns the raw JSON value of [title]. + * + * Unlike [title], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("title") @ExcludeMissing fun _title(): JsonField = title + + /** + * Returns the raw JSON value of [totalVotes]. + * + * Unlike [totalVotes], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("total_votes") @ExcludeMissing fun _totalVotes(): JsonField = totalVotes + + @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 [PollGetResultsResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PollGetResultsResponse]. */ + class Builder internal constructor() { + + private var chatId: JsonField = JsonMissing.of() + private var options: JsonField>? = null + private var pollId: JsonField = JsonMissing.of() + private var title: JsonField = JsonMissing.of() + private var totalVotes: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(pollGetResultsResponse: PollGetResultsResponse) = apply { + chatId = pollGetResultsResponse.chatId + options = pollGetResultsResponse.options.map { it.toMutableList() } + pollId = pollGetResultsResponse.pollId + title = pollGetResultsResponse.title + totalVotes = pollGetResultsResponse.totalVotes + additionalProperties = pollGetResultsResponse.additionalProperties.toMutableMap() + } + + fun chatId(chatId: String) = chatId(JsonField.of(chatId)) + + /** + * Sets [Builder.chatId] to an arbitrary JSON value. + * + * You should usually call [Builder.chatId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun chatId(chatId: JsonField) = apply { this.chatId = chatId } + + fun options(options: List