From d712abbfc3f4e8e54e8391ae34616bae45510b27 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:50:33 +0000 Subject: [PATCH 01/41] feat(api): manual updates --- .github/workflows/publish-sonatype.yml | 41 ++++++++++++ .github/workflows/release-doctor.yml | 24 +++++++ .release-please-manifest.json | 3 + .stats.yml | 2 +- README.md | 14 +++- bin/check-release-environment | 33 +++++++++ build.gradle.kts | 2 +- .../src/main/kotlin/phoebe.publish.gradle.kts | 6 +- .../main/kotlin/com/phoebe/api/core/Check.kt | 2 +- release-please-config.json | 67 +++++++++++++++++++ 10 files changed, 187 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/publish-sonatype.yml create mode 100644 .github/workflows/release-doctor.yml create mode 100644 .release-please-manifest.json create mode 100644 bin/check-release-environment create mode 100644 release-please-config.json diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml new file mode 100644 index 0000000..48cce0b --- /dev/null +++ b/.github/workflows/publish-sonatype.yml @@ -0,0 +1,41 @@ +# 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/phoebe-bird/phoebe-java/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@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + 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.PHOEBE_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.PHOEBE_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} + GPG_SIGNING_KEY: ${{ secrets.PHOEBE_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_PASSWORD: ${{ secrets.PHOEBE_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 new file mode 100644 index 0000000..e220472 --- /dev/null +++ b/.github/workflows/release-doctor.yml @@ -0,0 +1,24 @@ +name: Release Doctor +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + release_doctor: + name: release doctor + runs-on: ubuntu-latest + if: github.repository == 'phoebe-bird/phoebe-java' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') + + steps: + - uses: actions/checkout@v4 + + - name: Check release environment + run: | + bash ./bin/check-release-environment + env: + SONATYPE_USERNAME: ${{ secrets.PHOEBE_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.PHOEBE_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} + GPG_SIGNING_KEY: ${{ secrets.PHOEBE_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_PASSWORD: ${{ secrets.PHOEBE_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..c476280 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.0.1-alpha.0" +} \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 87b8e22..ca25ebc 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 25 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/personal-ijyk2f%2Fphoebe-3974e6147f98a3ce3fc4684fda2671e7a7dc7476ecdf42af7a5dc88725cc8f04.yml openapi_spec_hash: 9808c815a0b204fdee17a0abca108ab5 -config_hash: 90be8240e7a9b625b33329bb412c0bea +config_hash: 4f239d752d3041a8aa094ef5b66dbab6 diff --git a/README.md b/README.md index 9a45101..e694e59 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,26 @@ # Phoebe Java API Library + + [![Maven Central](https://img.shields.io/maven-central/v/com.phoebe.api/phoebe-java)](https://central.sonatype.com/artifact/com.phoebe.api/phoebe-java/0.0.1-alpha.0) [![javadoc](https://javadoc.io/badge2/com.phoebe.api/phoebe-java/0.0.1-alpha.0/javadoc.svg)](https://javadoc.io/doc/com.phoebe.api/phoebe-java/0.0.1-alpha.0) + + The Phoebe Java SDK provides convenient access to the [Phoebe REST API](https://science.ebird.org/en/use-ebird-data/download-ebird-data-products) from applications written in Java. It is generated with [Stainless](https://www.stainless.com/). + + The REST API documentation can be found on [science.ebird.org](https://science.ebird.org/en/use-ebird-data/download-ebird-data-products). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.phoebe.api/phoebe-java/0.0.1-alpha.0). + + ## Installation + + ### Gradle ```kotlin @@ -27,6 +37,8 @@ implementation("com.phoebe.api:phoebe-java:0.0.1-alpha.0") ``` + + ## Requirements This library requires Java 8 or later. @@ -583,4 +595,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/stainless-sdks/phoebe-java/issues) with questions, bugs, or suggestions. +We are keen for your feedback; please open an [issue](https://www.github.com/phoebe-bird/phoebe-java/issues) with questions, bugs, or suggestions. diff --git a/bin/check-release-environment b/bin/check-release-environment new file mode 100644 index 0000000..3a6a7b4 --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,33 @@ +#!/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/build.gradle.kts b/build.gradle.kts index 95d3c75..bccbd2e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.phoebe.api" - version = "0.0.1-alpha.0" + version = "0.0.1-alpha.0" // x-release-please-version } subprojects { diff --git a/buildSrc/src/main/kotlin/phoebe.publish.gradle.kts b/buildSrc/src/main/kotlin/phoebe.publish.gradle.kts index dd8ea61..3bf789a 100644 --- a/buildSrc/src/main/kotlin/phoebe.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/phoebe.publish.gradle.kts @@ -27,9 +27,9 @@ configure { } scm { - connection.set("scm:git:git://github.com/stainless-sdks/phoebe-java.git") - developerConnection.set("scm:git:git://github.com/stainless-sdks/phoebe-java.git") - url.set("https://github.com/stainless-sdks/phoebe-java") + connection.set("scm:git:git://github.com/phoebe-bird/phoebe-java.git") + developerConnection.set("scm:git:git://github.com/phoebe-bird/phoebe-java.git") + url.set("https://github.com/phoebe-bird/phoebe-java") } versionMapping { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/Check.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/Check.kt index 295fcbc..e8c3e22 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/Check.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/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/stainless-sdks/phoebe-java#jackson for more information. +See https://www.github.com/phoebe-bird/phoebe-java#jackson for more information. """ .trimIndent() } diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..8f98719 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,67 @@ +{ + "packages": { + ".": {} + }, + "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "include-v-in-tag": true, + "include-component-in-tag": false, + "versioning": "prerelease", + "prerelease": true, + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, + "pull-request-header": "Automated Release PR", + "pull-request-title-pattern": "release: ${version}", + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build System" + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + } + ], + "release-type": "simple", + "extra-files": [ + "README.md", + "build.gradle.kts" + ] +} \ No newline at end of file From 29fb6a253e46733a4c317823cfd1fa105d1dceeb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:51:22 +0000 Subject: [PATCH 02/41] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index ca25ebc..6913ec0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 25 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/personal-ijyk2f%2Fphoebe-3974e6147f98a3ce3fc4684fda2671e7a7dc7476ecdf42af7a5dc88725cc8f04.yml openapi_spec_hash: 9808c815a0b204fdee17a0abca108ab5 -config_hash: 4f239d752d3041a8aa094ef5b66dbab6 +config_hash: 51d14778da545342df105240e103d7dd From 34e57eb9eb6d57c100803d3e4a9eae9bdc1dbe23 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:55:28 +0000 Subject: [PATCH 03/41] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 6913ec0..8c14db5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 25 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/personal-ijyk2f%2Fphoebe-3974e6147f98a3ce3fc4684fda2671e7a7dc7476ecdf42af7a5dc88725cc8f04.yml openapi_spec_hash: 9808c815a0b204fdee17a0abca108ab5 -config_hash: 51d14778da545342df105240e103d7dd +config_hash: 17a571ff53308f9c391515734db807d2 From 5823abafce2a92fbb69a0f6c23db79a78b78f2a8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 06:13:10 +0000 Subject: [PATCH 04/41] fix(client): cancel okhttp call when future cancelled --- phoebe-java-client-okhttp/build.gradle.kts | 1 + .../phoebe/api/client/okhttp/OkHttpClient.kt | 34 ++++++++------ .../api/client/okhttp/OkHttpClientTest.kt | 44 +++++++++++++++++++ 3 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 phoebe-java-client-okhttp/src/test/kotlin/com/phoebe/api/client/okhttp/OkHttpClientTest.kt diff --git a/phoebe-java-client-okhttp/build.gradle.kts b/phoebe-java-client-okhttp/build.gradle.kts index fc320fc..d69a5de 100644 --- a/phoebe-java-client-okhttp/build.gradle.kts +++ b/phoebe-java-client-okhttp/build.gradle.kts @@ -11,4 +11,5 @@ dependencies { testImplementation(kotlin("test")) testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2") } diff --git a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt index ad75691..32c9047 100644 --- a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt +++ b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt @@ -13,6 +13,7 @@ import java.io.IOException import java.io.InputStream import java.net.Proxy import java.time.Duration +import java.util.concurrent.CancellationException import java.util.concurrent.CompletableFuture import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory @@ -29,8 +30,8 @@ import okhttp3.Response import okhttp3.logging.HttpLoggingInterceptor import okio.BufferedSink -class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpClient) : - HttpClient { +class OkHttpClient +private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClient) : HttpClient { override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { val call = newCall(request, requestOptions) @@ -50,20 +51,25 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC ): CompletableFuture { val future = CompletableFuture() - request.body?.run { future.whenComplete { _, _ -> close() } } - - newCall(request, requestOptions) - .enqueue( - object : Callback { - override fun onResponse(call: Call, response: Response) { - future.complete(response.toResponse()) - } + val call = newCall(request, requestOptions) + call.enqueue( + object : Callback { + override fun onResponse(call: Call, response: Response) { + future.complete(response.toResponse()) + } - override fun onFailure(call: Call, e: IOException) { - future.completeExceptionally(PhoebeIoException("Request failed", e)) - } + override fun onFailure(call: Call, e: IOException) { + future.completeExceptionally(PhoebeIoException("Request failed", e)) } - ) + } + ) + + future.whenComplete { _, e -> + if (e is CancellationException) { + call.cancel() + } + request.body?.close() + } return future } diff --git a/phoebe-java-client-okhttp/src/test/kotlin/com/phoebe/api/client/okhttp/OkHttpClientTest.kt b/phoebe-java-client-okhttp/src/test/kotlin/com/phoebe/api/client/okhttp/OkHttpClientTest.kt new file mode 100644 index 0000000..5ba90f8 --- /dev/null +++ b/phoebe-java-client-okhttp/src/test/kotlin/com/phoebe/api/client/okhttp/OkHttpClientTest.kt @@ -0,0 +1,44 @@ +package com.phoebe.api.client.okhttp + +import com.github.tomakehurst.wiremock.client.WireMock.* +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo +import com.github.tomakehurst.wiremock.junit5.WireMockTest +import com.phoebe.api.core.http.HttpMethod +import com.phoebe.api.core.http.HttpRequest +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.parallel.ResourceLock + +@WireMockTest +@ResourceLock("https://github.com/wiremock/wiremock/issues/169") +internal class OkHttpClientTest { + + private lateinit var baseUrl: String + private lateinit var httpClient: OkHttpClient + + @BeforeEach + fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { + baseUrl = wmRuntimeInfo.httpBaseUrl + httpClient = OkHttpClient.builder().build() + } + + @Test + fun executeAsync_whenFutureCancelled_cancelsUnderlyingCall() { + stubFor(post(urlPathEqualTo("/something")).willReturn(ok())) + val responseFuture = + httpClient.executeAsync( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build() + ) + val call = httpClient.okHttpClient.dispatcher.runningCalls().single() + + responseFuture.cancel(false) + + // Should have cancelled the underlying call + assertThat(call.isCanceled()).isTrue() + } +} From fe8a02007be585c2c162442e968a4fe8909eb39e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 08:08:34 +0000 Subject: [PATCH 05/41] docs: remove `$` for better copy-pasteabality --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e694e59..8cffb72 100644 --- a/README.md +++ b/README.md @@ -232,13 +232,13 @@ The SDK uses the standard [OkHttp logging interceptor](https://github.com/square Enable logging by setting the `PHOEBE_LOG` environment variable to `info`: ```sh -$ export PHOEBE_LOG=info +export PHOEBE_LOG=info ``` Or to `debug` for more verbose logging: ```sh -$ export PHOEBE_LOG=debug +export PHOEBE_LOG=debug ``` ## ProGuard and R8 From a145b94467e13633c59889cccd0c26b0b3789a44 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 07:24:55 +0000 Subject: [PATCH 06/41] feat(client): add `HttpRequest#url()` method --- LICENSE | 2 +- .../com/phoebe/api/core/http/HttpRequest.kt | 30 +++++ .../phoebe/api/core/http/HttpRequestTest.kt | 110 ++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/HttpRequestTest.kt diff --git a/LICENSE b/LICENSE index aa84a46..a69fada 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 Phoebe + Copyright 2026 Phoebe 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/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/HttpRequest.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/HttpRequest.kt index e398c05..6ddee7f 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/HttpRequest.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/HttpRequest.kt @@ -2,6 +2,7 @@ package com.phoebe.api.core.http import com.phoebe.api.core.checkRequired import com.phoebe.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/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/HttpRequestTest.kt b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/HttpRequestTest.kt new file mode 100644 index 0000000..063a971 --- /dev/null +++ b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/HttpRequestTest.kt @@ -0,0 +1,110 @@ +package com.phoebe.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 7754ce1495022f309ff26d5c2f06f3c4c8e913b7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 07:35:41 +0000 Subject: [PATCH 07/41] docs: prominently feature MCP server setup in root SDK readmes --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 8cffb72..7aaccd5 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,15 @@ The Phoebe Java SDK provides convenient access to the [Phoebe REST API](https:// It is generated with [Stainless](https://www.stainless.com/). +## MCP Server + +Use the Phoebe MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. + +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=phoebe-ebird-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInBob2ViZS1lYmlyZC1tY3AiXX0) +[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22phoebe-ebird-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22phoebe-ebird-mcp%22%5D%7D) + +> Note: You may need to set environment variables in your MCP client. + The REST API documentation can be found on [science.ebird.org](https://science.ebird.org/en/use-ebird-data/download-ebird-data-products). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.phoebe.api/phoebe-java/0.0.1-alpha.0). From ef7c2660841ba59c269caa78b58f9a9f59fa162c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 06:03:19 +0000 Subject: [PATCH 08/41] feat(client): allow configuring dispatcher executor service --- .../phoebe/api/client/okhttp/OkHttpClient.kt | 9 ++++++++ .../api/client/okhttp/PhoebeOkHttpClient.kt | 22 +++++++++++++++++++ .../client/okhttp/PhoebeOkHttpClientAsync.kt | 22 +++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt index 32c9047..b52aa5b 100644 --- a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt +++ b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/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 @@ -200,6 +202,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 @@ -210,6 +213,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 } @@ -231,6 +238,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) { diff --git a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClient.kt b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClient.kt index 57aa49e..7e9e5ad 100644 --- a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClient.kt +++ b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClient.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 PhoebeOkHttpClient 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)`. */ @@ -296,6 +317,7 @@ class PhoebeOkHttpClient private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) diff --git a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClientAsync.kt b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClientAsync.kt index e133879..4fba04c 100644 --- a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClientAsync.kt +++ b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClientAsync.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 PhoebeOkHttpClientAsync 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)`. */ @@ -296,6 +317,7 @@ class PhoebeOkHttpClientAsync private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) From 37c89f8c816525461bce82b5550d796ff1ff3023 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 12:21:41 +0000 Subject: [PATCH 09/41] chore(internal): support uploading Maven repo artifacts to stainless package server --- .github/workflows/ci.yml | 18 ++++ .../src/main/kotlin/phoebe.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 6d4e261..4abc195 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/phoebe-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/phoebe-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/phoebe-java' + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + PROJECT: phoebe-java + run: ./scripts/upload-artifacts test: timeout-minutes: 15 name: test diff --git a/buildSrc/src/main/kotlin/phoebe.publish.gradle.kts b/buildSrc/src/main/kotlin/phoebe.publish.gradle.kts index 3bf789a..a6386d7 100644 --- a/buildSrc/src/main/kotlin/phoebe.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/phoebe.publish.gradle.kts @@ -40,6 +40,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 6a0f2cab131804296e2b29cc2e29c58de3603a2b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 05:18:33 +0000 Subject: [PATCH 10/41] 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 9d5f042b85f9bdaec3a56ad6ea180a32f6a5f454 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 07:44:48 +0000 Subject: [PATCH 11/41] chore: test on Jackson 2.14.0 to avoid encountering FasterXML/jackson-databind#3240 in tests fix: date time deserialization leniency --- README.md | 2 ++ phoebe-java-core/build.gradle.kts | 18 +++++----- .../com/phoebe/api/core/ObjectMappers.kt | 33 ++++++++++++------- .../com/phoebe/api/core/ObjectMappersTest.kt | 16 +++------ phoebe-java-proguard-test/build.gradle.kts | 2 +- 5 files changed, 38 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 7aaccd5..5027fa2 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,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/phoebe-java-core/build.gradle.kts b/phoebe-java-core/build.gradle.kts index a65d57c..bf0d85a 100644 --- a/phoebe-java-core/build.gradle.kts +++ b/phoebe-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/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ObjectMappers.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ObjectMappers.kt index 8c8d7e2..01f983d 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ObjectMappers.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/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/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt index 35ca1ac..4979954 100644 --- a/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt +++ b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt @@ -3,7 +3,7 @@ package com.phoebe.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/phoebe-java-proguard-test/build.gradle.kts b/phoebe-java-proguard-test/build.gradle.kts index 932d96a..7bcadd4 100644 --- a/phoebe-java-proguard-test/build.gradle.kts +++ b/phoebe-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 da49cb77739c9becf5d45b12095298950f1e32f9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 07:48:12 +0000 Subject: [PATCH 12/41] 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 d00944fd323009658808104c8a4b3954211b3559 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 07:54:10 +0000 Subject: [PATCH 13/41] fix(client): disallow coercion from float to int --- .../src/main/kotlin/com/phoebe/api/core/ObjectMappers.kt | 1 + .../src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ObjectMappers.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ObjectMappers.kt index 01f983d..d69243e 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ObjectMappers.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/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/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt index 4979954..ae0747a 100644 --- a/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt +++ b/phoebe-java-core/src/test/kotlin/com/phoebe/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 3a146bbdb3ab84f558391f3b8e6bc7e2c8fd77f6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 07:55:19 +0000 Subject: [PATCH 14/41] 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 4abc195..ffa2c80 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/phoebe-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 48cce0b..1730207 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 e220472..3791b5c 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'phoebe-bird/phoebe-java' && (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 7c71f9dc52f85d1a055e25f5d940ac1fc6d807b0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 07:57:45 +0000 Subject: [PATCH 15/41] fix(client): fully respect max retries fix(client): send retry count header for max retries 0 chore(internal): depend on packages directly in example --- .../phoebe/api/client/okhttp/OkHttpClient.kt | 2 ++ .../api/core/http/RetryingHttpClient.kt | 20 +++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt index b52aa5b..6cc8418 100644 --- a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt +++ b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt @@ -232,6 +232,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/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt index d6041fe..5245d87 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/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 75d7ae3dc40b246a7fe1e4a0316122c579779edd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 07:59:02 +0000 Subject: [PATCH 16/41] 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 ffa2c80..22135c2 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 1730207..3a4ee30 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 cf7eb239f388de322581a476a6e6845cebd5e019 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:56:05 +0000 Subject: [PATCH 17/41] 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 d9f18bd66b86423c4ae710ea0987fe35f53ed457 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:57:04 +0000 Subject: [PATCH 18/41] feat(client): send `X-Stainless-Kotlin-Version` header --- .../src/main/kotlin/com/phoebe/api/core/ClientOptions.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ClientOptions.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ClientOptions.kt index cadc2c5..9efbc61 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ClientOptions.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ClientOptions.kt @@ -402,6 +402,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("X-eBirdApiToken", it) From adfd7da05a09ef5622316700c031b6ac6ef4d05f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 06:59:59 +0000 Subject: [PATCH 19/41] chore(internal): correct cache invalidation for `SKIP_MOCK_TESTS` --- buildSrc/src/main/kotlin/phoebe.kotlin.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/buildSrc/src/main/kotlin/phoebe.kotlin.gradle.kts b/buildSrc/src/main/kotlin/phoebe.kotlin.gradle.kts index 40e3ce8..9478991 100644 --- a/buildSrc/src/main/kotlin/phoebe.kotlin.gradle.kts +++ b/buildSrc/src/main/kotlin/phoebe.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 50bb540673b947b6f5b2da24bb3cac46e3ca498a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 07:03:25 +0000 Subject: [PATCH 20/41] fix(client): preserve time zone in lenient date-time parsing --- .../com/phoebe/api/core/ObjectMappers.kt | 19 +++++---- .../com/phoebe/api/core/ObjectMappersTest.kt | 41 +++++++++++++++---- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ObjectMappers.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ObjectMappers.kt index d69243e..db714d1 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ObjectMappers.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/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/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt index ae0747a..115b997 100644 --- a/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt +++ b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ObjectMappersTest.kt @@ -3,12 +3,14 @@ package com.phoebe.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 43107c0efbf857c052a1ce799f14a45add565375 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 24 Jan 2026 06:44:49 +0000 Subject: [PATCH 21/41] 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 22135c2..2208be4 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/phoebe-java' id: github-oidc - uses: actions/github-script@v6 + uses: actions/github-script@v8 with: script: core.setOutput('github_token', await core.getIDToken()); From 704a4e190b022602ad545cf926ef21ce4bac5d96 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 07:32:57 +0000 Subject: [PATCH 22/41] chore(internal): codegen related update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5027fa2..1144a6f 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ It is generated with [Stainless](https://www.stainless.com/). Use the Phoebe MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. -[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=phoebe-ebird-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInBob2ViZS1lYmlyZC1tY3AiXX0) -[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22phoebe-ebird-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22phoebe-ebird-mcp%22%5D%7D) +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=phoebe-ebird-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInBob2ViZS1lYmlyZC1tY3AiXSwiZW52Ijp7IkVCSVJEX0FQSV9LRVkiOiJNeSBBUEkgS2V5In19) +[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22phoebe-ebird-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22phoebe-ebird-mcp%22%5D%2C%22env%22%3A%7B%22EBIRD_API_KEY%22%3A%22My%20API%20Key%22%7D%7D) > Note: You may need to set environment variables in your MCP client. From 78f64241e6e1a7f11b3004ea3b40e282688e473d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 31 Jan 2026 08:31:27 +0000 Subject: [PATCH 23/41] chore(internal): codegen related update --- 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 fa744740ab0421e1a3ed33aad5952fde2e80c4df Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 7 Feb 2026 10:19:36 +0000 Subject: [PATCH 24/41] chore(internal): codegen related update --- phoebe-java-client-okhttp/build.gradle.kts | 2 +- phoebe-java-core/build.gradle.kts | 2 +- phoebe-java-proguard-test/build.gradle.kts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/phoebe-java-client-okhttp/build.gradle.kts b/phoebe-java-client-okhttp/build.gradle.kts index d69a5de..6ae5611 100644 --- a/phoebe-java-client-okhttp/build.gradle.kts +++ b/phoebe-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/phoebe-java-core/build.gradle.kts b/phoebe-java-core/build.gradle.kts index bf0d85a..c5441df 100644 --- a/phoebe-java-core/build.gradle.kts +++ b/phoebe-java-core/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation(project(":phoebe-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/phoebe-java-proguard-test/build.gradle.kts b/phoebe-java-proguard-test/build.gradle.kts index 7bcadd4..248bccd 100644 --- a/phoebe-java-proguard-test/build.gradle.kts +++ b/phoebe-java-proguard-test/build.gradle.kts @@ -18,7 +18,7 @@ dependencies { testImplementation(project(":phoebe-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 17f6183f74d414255db7fe82cbc6e73b09430d06 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 06:28:45 +0000 Subject: [PATCH 25/41] chore(internal): codegen related update --- .../com/phoebe/api/TestServerExtension.kt | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/phoebe-java-core/src/test/kotlin/com/phoebe/api/TestServerExtension.kt b/phoebe-java-core/src/test/kotlin/com/phoebe/api/TestServerExtension.kt index d533d2d..9a24ecf 100644 --- a/phoebe-java-core/src/test/kotlin/com/phoebe/api/TestServerExtension.kt +++ b/phoebe-java-core/src/test/kotlin/com/phoebe/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 20826641ea001336618b19ceaf63acd87ed82d9f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 06:47:06 +0000 Subject: [PATCH 26/41] chore(internal): codegen related update --- README.md | 19 ++++++++ .../phoebe/api/client/okhttp/OkHttpClient.kt | 44 ++++++++++++++++++- .../api/client/okhttp/PhoebeOkHttpClient.kt | 44 +++++++++++++++++++ .../client/okhttp/PhoebeOkHttpClientAsync.kt | 44 +++++++++++++++++++ 4 files changed, 150 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1144a6f..27bc751 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,25 @@ PhoebeClient client = PhoebeOkHttpClient.builder() .build(); ``` +### Connection pooling + +To customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods: + +```java +import com.phoebe.api.client.PhoebeClient; +import com.phoebe.api.client.okhttp.PhoebeOkHttpClient; +import java.time.Duration; + +PhoebeClient client = PhoebeOkHttpClient.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/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt index 6cc8418..755adb8 100644 --- a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/OkHttpClient.kt +++ b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/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) @@ -202,6 +204,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 @@ -213,6 +217,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 } @@ -242,6 +268,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) { diff --git a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClient.kt b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClient.kt index 7e9e5ad..948b72b 100644 --- a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClient.kt +++ b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClient.kt @@ -47,6 +47,8 @@ class PhoebeOkHttpClient 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 PhoebeOkHttpClient 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. * @@ -317,6 +359,8 @@ class PhoebeOkHttpClient private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .maxIdleConnections(maxIdleConnections) + .keepAliveDuration(keepAliveDuration) .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) diff --git a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClientAsync.kt b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClientAsync.kt index 4fba04c..a110af7 100644 --- a/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClientAsync.kt +++ b/phoebe-java-client-okhttp/src/main/kotlin/com/phoebe/api/client/okhttp/PhoebeOkHttpClientAsync.kt @@ -47,6 +47,8 @@ class PhoebeOkHttpClientAsync 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 PhoebeOkHttpClientAsync 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. * @@ -317,6 +359,8 @@ class PhoebeOkHttpClientAsync private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .maxIdleConnections(maxIdleConnections) + .keepAliveDuration(keepAliveDuration) .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) From 26cd70c6547384e153a6abf88178fbed6e8c2951 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 08:50:42 +0000 Subject: [PATCH 27/41] chore(internal): codegen related update --- phoebe-java-core/build.gradle.kts | 2 - .../kotlin/com/phoebe/api/core/Properties.kt | 6 +- .../phoebe/api/core/http/HttpRequestBodies.kt | 295 +++++-- .../api/core/http/HttpRequestBodiesTest.kt | 729 ++++++++++++++++++ 4 files changed, 949 insertions(+), 83 deletions(-) create mode 100644 phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/HttpRequestBodiesTest.kt diff --git a/phoebe-java-core/build.gradle.kts b/phoebe-java-core/build.gradle.kts index c5441df..ce7620e 100644 --- a/phoebe-java-core/build.gradle.kts +++ b/phoebe-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(":phoebe-java-client-okhttp")) diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/Properties.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/Properties.kt index a132d4f..c5b53a3 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/Properties.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/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 = - PhoebeClient::class.java.`package`.implementationVersion ?: "unknown" + PhoebeClient::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/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/HttpRequestBodies.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/HttpRequestBodies.kt index d274acd..bd6fcdb 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/HttpRequestBodies.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/HttpRequestBodies.kt @@ -8,13 +8,13 @@ import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.databind.node.JsonNodeType import com.phoebe.api.core.MultipartField +import com.phoebe.api.core.toImmutable import com.phoebe.api.errors.PhoebeInvalidDataException +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 PhoebeInvalidDataException( - "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 PhoebeInvalidDataException("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 PhoebeInvalidDataException( + "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 PhoebeInvalidDataException("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/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/HttpRequestBodiesTest.kt b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/HttpRequestBodiesTest.kt new file mode 100644 index 0000000..ca3d73d --- /dev/null +++ b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/HttpRequestBodiesTest.kt @@ -0,0 +1,729 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.phoebe.api.core.http + +import com.phoebe.api.core.MultipartField +import com.phoebe.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 b07058d9f6e68617a2c01194deabd50547848f87 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 08:39:11 +0000 Subject: [PATCH 28/41] chore(internal): codegen related update --- .../com/phoebe/api/core/http/RetryingHttpClient.kt | 2 ++ .../phoebe/api/core/http/RetryingHttpClientTest.kt | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt index 5245d87..e573807 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt @@ -1,3 +1,5 @@ +// File generated from our OpenAPI spec by Stainless. + package com.phoebe.api.core.http import com.phoebe.api.core.DefaultSleeper diff --git a/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt index 7825059..6579be5 100644 --- a/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt +++ b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt @@ -1,6 +1,17 @@ +// File generated from our OpenAPI spec by Stainless. + package com.phoebe.api.core.http -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 9b9b899e5b9186438c76ddc90a0b2fe65a21ef17 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 18:38:14 +0000 Subject: [PATCH 29/41] chore(internal): codegen related update --- .../api/services/async/ProductServiceAsync.kt | 62 +++++++++++++++++++ .../services/async/ProductServiceAsyncImpl.kt | 62 +++++++++++++++++++ .../api/services/async/RefServiceAsync.kt | 8 +++ .../api/services/async/RefServiceAsyncImpl.kt | 8 +++ .../async/data/ObservationServiceAsync.kt | 14 +++++ .../async/data/ObservationServiceAsyncImpl.kt | 14 +++++ .../data/observations/GeoServiceAsync.kt | 14 +++++ .../data/observations/GeoServiceAsyncImpl.kt | 14 +++++ .../data/observations/NearestServiceAsync.kt | 14 +++++ .../observations/NearestServiceAsyncImpl.kt | 14 +++++ .../data/observations/RecentServiceAsync.kt | 48 ++++++++++++++ .../observations/RecentServiceAsyncImpl.kt | 48 ++++++++++++++ .../observations/geo/RecentServiceAsync.kt | 34 ++++++++++ .../geo/RecentServiceAsyncImpl.kt | 34 ++++++++++ .../geo/recent/NotableServiceAsync.kt | 6 ++ .../geo/recent/NotableServiceAsyncImpl.kt | 6 ++ .../geo/recent/SpecieServiceAsync.kt | 6 ++ .../geo/recent/SpecieServiceAsyncImpl.kt | 6 ++ .../nearest/GeoSpecieServiceAsync.kt | 6 ++ .../nearest/GeoSpecieServiceAsyncImpl.kt | 6 ++ .../recent/HistoricServiceAsync.kt | 6 ++ .../recent/HistoricServiceAsyncImpl.kt | 6 ++ .../recent/NotableServiceAsync.kt | 6 ++ .../recent/NotableServiceAsyncImpl.kt | 6 ++ .../observations/recent/SpecieServiceAsync.kt | 6 ++ .../recent/SpecieServiceAsyncImpl.kt | 6 ++ .../async/product/ChecklistServiceAsync.kt | 6 ++ .../product/ChecklistServiceAsyncImpl.kt | 6 ++ .../async/product/ListServiceAsync.kt | 18 ++++++ .../async/product/ListServiceAsyncImpl.kt | 18 ++++++ .../async/product/SpeciesListServiceAsync.kt | 6 ++ .../product/SpeciesListServiceAsyncImpl.kt | 6 ++ .../async/product/StatServiceAsync.kt | 6 ++ .../async/product/StatServiceAsyncImpl.kt | 6 ++ .../async/product/Top100ServiceAsync.kt | 6 ++ .../async/product/Top100ServiceAsyncImpl.kt | 6 ++ .../product/lists/HistoricalServiceAsync.kt | 6 ++ .../lists/HistoricalServiceAsyncImpl.kt | 6 ++ .../services/async/ref/HotspotServiceAsync.kt | 20 ++++++ .../async/ref/HotspotServiceAsyncImpl.kt | 20 ++++++ .../services/async/ref/RegionServiceAsync.kt | 6 ++ .../async/ref/RegionServiceAsyncImpl.kt | 6 ++ .../async/ref/hotspot/GeoServiceAsync.kt | 4 ++ .../async/ref/hotspot/GeoServiceAsyncImpl.kt | 4 ++ .../async/ref/hotspot/InfoServiceAsync.kt | 4 ++ .../async/ref/hotspot/InfoServiceAsyncImpl.kt | 4 ++ .../async/ref/region/AdjacentServiceAsync.kt | 1 + .../ref/region/AdjacentServiceAsyncImpl.kt | 1 + .../async/ref/region/InfoServiceAsync.kt | 1 + .../async/ref/region/InfoServiceAsyncImpl.kt | 1 + .../async/ref/region/ListServiceAsync.kt | 1 + .../async/ref/region/ListServiceAsyncImpl.kt | 1 + .../api/services/blocking/ProductService.kt | 62 +++++++++++++++++++ .../services/blocking/ProductServiceImpl.kt | 62 +++++++++++++++++++ .../api/services/blocking/RefService.kt | 8 +++ .../api/services/blocking/RefServiceImpl.kt | 8 +++ .../blocking/data/ObservationService.kt | 14 +++++ .../blocking/data/ObservationServiceImpl.kt | 14 +++++ .../blocking/data/observations/GeoService.kt | 14 +++++ .../data/observations/GeoServiceImpl.kt | 14 +++++ .../data/observations/NearestService.kt | 14 +++++ .../data/observations/NearestServiceImpl.kt | 14 +++++ .../data/observations/RecentService.kt | 48 ++++++++++++++ .../data/observations/RecentServiceImpl.kt | 48 ++++++++++++++ .../data/observations/geo/RecentService.kt | 34 ++++++++++ .../observations/geo/RecentServiceImpl.kt | 34 ++++++++++ .../observations/geo/recent/NotableService.kt | 6 ++ .../geo/recent/NotableServiceImpl.kt | 6 ++ .../observations/geo/recent/SpecieService.kt | 6 ++ .../geo/recent/SpecieServiceImpl.kt | 6 ++ .../observations/nearest/GeoSpecieService.kt | 6 ++ .../nearest/GeoSpecieServiceImpl.kt | 6 ++ .../observations/recent/HistoricService.kt | 6 ++ .../recent/HistoricServiceImpl.kt | 6 ++ .../observations/recent/NotableService.kt | 6 ++ .../observations/recent/NotableServiceImpl.kt | 6 ++ .../data/observations/recent/SpecieService.kt | 6 ++ .../observations/recent/SpecieServiceImpl.kt | 6 ++ .../blocking/product/ChecklistService.kt | 6 ++ .../blocking/product/ChecklistServiceImpl.kt | 6 ++ .../services/blocking/product/ListService.kt | 18 ++++++ .../blocking/product/ListServiceImpl.kt | 18 ++++++ .../blocking/product/SpeciesListService.kt | 6 ++ .../product/SpeciesListServiceImpl.kt | 6 ++ .../services/blocking/product/StatService.kt | 6 ++ .../blocking/product/StatServiceImpl.kt | 6 ++ .../blocking/product/Top100Service.kt | 6 ++ .../blocking/product/Top100ServiceImpl.kt | 6 ++ .../product/lists/HistoricalService.kt | 6 ++ .../product/lists/HistoricalServiceImpl.kt | 6 ++ .../services/blocking/ref/HotspotService.kt | 20 ++++++ .../blocking/ref/HotspotServiceImpl.kt | 20 ++++++ .../services/blocking/ref/RegionService.kt | 6 ++ .../blocking/ref/RegionServiceImpl.kt | 6 ++ .../blocking/ref/hotspot/GeoService.kt | 4 ++ .../blocking/ref/hotspot/GeoServiceImpl.kt | 4 ++ .../blocking/ref/hotspot/InfoService.kt | 4 ++ .../blocking/ref/hotspot/InfoServiceImpl.kt | 4 ++ .../blocking/ref/region/AdjacentService.kt | 1 + .../ref/region/AdjacentServiceImpl.kt | 1 + .../blocking/ref/region/InfoService.kt | 1 + .../blocking/ref/region/InfoServiceImpl.kt | 1 + .../blocking/ref/region/ListService.kt | 1 + .../blocking/ref/region/ListServiceImpl.kt | 1 + 104 files changed, 1260 insertions(+) diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ProductServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ProductServiceAsync.kt index 1eb0c21..c26d846 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ProductServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ProductServiceAsync.kt @@ -24,14 +24,45 @@ interface ProductServiceAsync { */ fun withOptions(modifier: Consumer): ProductServiceAsync + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun lists(): ListServiceAsync + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ fun top100(): Top100ServiceAsync + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ fun stats(): StatServiceAsync + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ fun speciesList(): SpeciesListServiceAsync + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ fun checklist(): ChecklistServiceAsync /** @@ -48,14 +79,45 @@ interface ProductServiceAsync { modifier: Consumer ): ProductServiceAsync.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun lists(): ListServiceAsync.WithRawResponse + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ fun top100(): Top100ServiceAsync.WithRawResponse + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ fun stats(): StatServiceAsync.WithRawResponse + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ fun speciesList(): SpeciesListServiceAsync.WithRawResponse + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ fun checklist(): ChecklistServiceAsync.WithRawResponse } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ProductServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ProductServiceAsyncImpl.kt index 2cce22f..1e9219e 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ProductServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ProductServiceAsyncImpl.kt @@ -41,14 +41,45 @@ class ProductServiceAsyncImpl internal constructor(private val clientOptions: Cl override fun withOptions(modifier: Consumer): ProductServiceAsync = ProductServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun lists(): ListServiceAsync = lists + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ override fun top100(): Top100ServiceAsync = top100 + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ override fun stats(): StatServiceAsync = stats + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ override fun speciesList(): SpeciesListServiceAsync = speciesList + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ override fun checklist(): ChecklistServiceAsync = checklist class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -81,14 +112,45 @@ class ProductServiceAsyncImpl internal constructor(private val clientOptions: Cl clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun lists(): ListServiceAsync.WithRawResponse = lists + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ override fun top100(): Top100ServiceAsync.WithRawResponse = top100 + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ override fun stats(): StatServiceAsync.WithRawResponse = stats + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ override fun speciesList(): SpeciesListServiceAsync.WithRawResponse = speciesList + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ override fun checklist(): ChecklistServiceAsync.WithRawResponse = checklist } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/RefServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/RefServiceAsync.kt index 50c145d..f3dd9b7 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/RefServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/RefServiceAsync.kt @@ -24,6 +24,10 @@ interface RefServiceAsync { fun region(): RegionServiceAsync + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ fun hotspot(): HotspotServiceAsync fun taxonomy(): TaxonomyServiceAsync @@ -40,6 +44,10 @@ interface RefServiceAsync { fun region(): RegionServiceAsync.WithRawResponse + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ fun hotspot(): HotspotServiceAsync.WithRawResponse fun taxonomy(): TaxonomyServiceAsync.WithRawResponse diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/RefServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/RefServiceAsyncImpl.kt index ef3b52d..e8650fa 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/RefServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/RefServiceAsyncImpl.kt @@ -31,6 +31,10 @@ class RefServiceAsyncImpl internal constructor(private val clientOptions: Client override fun region(): RegionServiceAsync = region + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ override fun hotspot(): HotspotServiceAsync = hotspot override fun taxonomy(): TaxonomyServiceAsync = taxonomy @@ -59,6 +63,10 @@ class RefServiceAsyncImpl internal constructor(private val clientOptions: Client override fun region(): RegionServiceAsync.WithRawResponse = region + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ override fun hotspot(): HotspotServiceAsync.WithRawResponse = hotspot override fun taxonomy(): TaxonomyServiceAsync.WithRawResponse = taxonomy diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/ObservationServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/ObservationServiceAsync.kt index 80b23e6..4c9b6ee 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/ObservationServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/ObservationServiceAsync.kt @@ -22,6 +22,13 @@ interface ObservationServiceAsync { */ fun withOptions(modifier: Consumer): ObservationServiceAsync + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun recent(): RecentServiceAsync fun geo(): GeoServiceAsync @@ -43,6 +50,13 @@ interface ObservationServiceAsync { modifier: Consumer ): ObservationServiceAsync.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun recent(): RecentServiceAsync.WithRawResponse fun geo(): GeoServiceAsync.WithRawResponse diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/ObservationServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/ObservationServiceAsyncImpl.kt index 908e9d7..51c9f59 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/ObservationServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/ObservationServiceAsyncImpl.kt @@ -29,6 +29,13 @@ class ObservationServiceAsyncImpl internal constructor(private val clientOptions override fun withOptions(modifier: Consumer): ObservationServiceAsync = ObservationServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun recent(): RecentServiceAsync = recent override fun geo(): GeoServiceAsync = geo @@ -57,6 +64,13 @@ class ObservationServiceAsyncImpl internal constructor(private val clientOptions clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun recent(): RecentServiceAsync.WithRawResponse = recent override fun geo(): GeoServiceAsync.WithRawResponse = geo diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/GeoServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/GeoServiceAsync.kt index 7e66a63..6843a2e 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/GeoServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/GeoServiceAsync.kt @@ -20,6 +20,13 @@ interface GeoServiceAsync { */ fun withOptions(modifier: Consumer): GeoServiceAsync + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun recent(): RecentServiceAsync /** A view of [GeoServiceAsync] that provides access to raw HTTP responses for each method. */ @@ -32,6 +39,13 @@ interface GeoServiceAsync { */ fun withOptions(modifier: Consumer): GeoServiceAsync.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun recent(): RecentServiceAsync.WithRawResponse } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/GeoServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/GeoServiceAsyncImpl.kt index 9fedf02..6095989 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/GeoServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/GeoServiceAsyncImpl.kt @@ -21,6 +21,13 @@ class GeoServiceAsyncImpl internal constructor(private val clientOptions: Client override fun withOptions(modifier: Consumer): GeoServiceAsync = GeoServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun recent(): RecentServiceAsync = recent class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -37,6 +44,13 @@ class GeoServiceAsyncImpl internal constructor(private val clientOptions: Client clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun recent(): RecentServiceAsync.WithRawResponse = recent } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/NearestServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/NearestServiceAsync.kt index 68e8bcd..1e647ad 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/NearestServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/NearestServiceAsync.kt @@ -20,6 +20,13 @@ interface NearestServiceAsync { */ fun withOptions(modifier: Consumer): NearestServiceAsync + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun geoSpecies(): GeoSpecieServiceAsync /** @@ -36,6 +43,13 @@ interface NearestServiceAsync { modifier: Consumer ): NearestServiceAsync.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun geoSpecies(): GeoSpecieServiceAsync.WithRawResponse } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/NearestServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/NearestServiceAsyncImpl.kt index d9bb0b2..d9c5827 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/NearestServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/NearestServiceAsyncImpl.kt @@ -23,6 +23,13 @@ class NearestServiceAsyncImpl internal constructor(private val clientOptions: Cl override fun withOptions(modifier: Consumer): NearestServiceAsync = NearestServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun geoSpecies(): GeoSpecieServiceAsync = geoSpecies class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -39,6 +46,13 @@ class NearestServiceAsyncImpl internal constructor(private val clientOptions: Cl clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun geoSpecies(): GeoSpecieServiceAsync.WithRawResponse = geoSpecies } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/RecentServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/RecentServiceAsync.kt index ed439c1..5b2a563 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/RecentServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/RecentServiceAsync.kt @@ -13,6 +13,12 @@ import com.phoebe.api.services.async.data.observations.recent.SpecieServiceAsync import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface RecentServiceAsync { /** @@ -27,10 +33,31 @@ interface RecentServiceAsync { */ fun withOptions(modifier: Consumer): RecentServiceAsync + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun notable(): NotableServiceAsync + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun species(): SpecieServiceAsync + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun historic(): HistoricServiceAsync /** @@ -86,10 +113,31 @@ interface RecentServiceAsync { modifier: Consumer ): RecentServiceAsync.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun notable(): NotableServiceAsync.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun species(): SpecieServiceAsync.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun historic(): HistoricServiceAsync.WithRawResponse /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/RecentServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/RecentServiceAsyncImpl.kt index df5842d..7d15ab1 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/RecentServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/RecentServiceAsyncImpl.kt @@ -27,6 +27,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class RecentServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : RecentServiceAsync { @@ -45,10 +51,31 @@ class RecentServiceAsyncImpl internal constructor(private val clientOptions: Cli override fun withOptions(modifier: Consumer): RecentServiceAsync = RecentServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun notable(): NotableServiceAsync = notable + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun species(): SpecieServiceAsync = species + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun historic(): HistoricServiceAsync = historic override fun list( @@ -83,10 +110,31 @@ class RecentServiceAsyncImpl internal constructor(private val clientOptions: Cli clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun notable(): NotableServiceAsync.WithRawResponse = notable + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun species(): SpecieServiceAsync.WithRawResponse = species + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun historic(): HistoricServiceAsync.WithRawResponse = historic private val listHandler: Handler> = diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/RecentServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/RecentServiceAsync.kt index 0c1b6bb..33f3dd8 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/RecentServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/RecentServiceAsync.kt @@ -12,6 +12,12 @@ import com.phoebe.api.services.async.data.observations.geo.recent.SpecieServiceA import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface RecentServiceAsync { /** @@ -26,8 +32,22 @@ interface RecentServiceAsync { */ fun withOptions(modifier: Consumer): RecentServiceAsync + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun species(): SpecieServiceAsync + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun notable(): NotableServiceAsync /** @@ -58,8 +78,22 @@ interface RecentServiceAsync { modifier: Consumer ): RecentServiceAsync.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun species(): SpecieServiceAsync.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun notable(): NotableServiceAsync.WithRawResponse /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/RecentServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/RecentServiceAsyncImpl.kt index c6f6595..bf60ac8 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/RecentServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/RecentServiceAsyncImpl.kt @@ -23,6 +23,12 @@ import com.phoebe.api.services.async.data.observations.geo.recent.SpecieServiceA import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class RecentServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : RecentServiceAsync { @@ -39,8 +45,22 @@ class RecentServiceAsyncImpl internal constructor(private val clientOptions: Cli override fun withOptions(modifier: Consumer): RecentServiceAsync = RecentServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun species(): SpecieServiceAsync = species + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun notable(): NotableServiceAsync = notable override fun list( @@ -71,8 +91,22 @@ class RecentServiceAsyncImpl internal constructor(private val clientOptions: Cli clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun species(): SpecieServiceAsync.WithRawResponse = species + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun notable(): NotableServiceAsync.WithRawResponse = notable private val listHandler: Handler> = diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/NotableServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/NotableServiceAsync.kt index 0e948e3..c502f50 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/NotableServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/NotableServiceAsync.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.geo.recent.notable.NotableListPar import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface NotableServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/NotableServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/NotableServiceAsyncImpl.kt index dd8f63d..9fba1f8 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/NotableServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/NotableServiceAsyncImpl.kt @@ -19,6 +19,12 @@ import com.phoebe.api.models.data.observations.geo.recent.notable.NotableListPar import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class NotableServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : NotableServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/SpecieServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/SpecieServiceAsync.kt index 955b3b5..8b9e063 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/SpecieServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/SpecieServiceAsync.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.geo.recent.species.SpecieListPara import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface SpecieServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/SpecieServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/SpecieServiceAsyncImpl.kt index 5cbb0de..97d405a 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/SpecieServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/geo/recent/SpecieServiceAsyncImpl.kt @@ -21,6 +21,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class SpecieServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : SpecieServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/nearest/GeoSpecieServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/nearest/GeoSpecieServiceAsync.kt index 0c1b62a..b74e8db 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/nearest/GeoSpecieServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/nearest/GeoSpecieServiceAsync.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.nearest.geospecies.GeoSpecieListP import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface GeoSpecieServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/nearest/GeoSpecieServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/nearest/GeoSpecieServiceAsyncImpl.kt index 41870c7..6125a1c 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/nearest/GeoSpecieServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/nearest/GeoSpecieServiceAsyncImpl.kt @@ -21,6 +21,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class GeoSpecieServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : GeoSpecieServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/HistoricServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/HistoricServiceAsync.kt index 629cd8a..22190b2 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/HistoricServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/HistoricServiceAsync.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.recent.historic.HistoricListParam import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface HistoricServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/HistoricServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/HistoricServiceAsyncImpl.kt index e39f932..b5745df 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/HistoricServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/HistoricServiceAsyncImpl.kt @@ -21,6 +21,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class HistoricServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : HistoricServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/NotableServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/NotableServiceAsync.kt index c114452..d9674a5 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/NotableServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/NotableServiceAsync.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.recent.notable.NotableListParams import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface NotableServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/NotableServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/NotableServiceAsyncImpl.kt index 7f26597..f173eb7 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/NotableServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/NotableServiceAsyncImpl.kt @@ -21,6 +21,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class NotableServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : NotableServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/SpecieServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/SpecieServiceAsync.kt index 2281fb2..f34f4fd 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/SpecieServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/SpecieServiceAsync.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.recent.species.SpecieRetrievePara import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface SpecieServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/SpecieServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/SpecieServiceAsyncImpl.kt index 3bf7a4d..fbe2e45 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/SpecieServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/data/observations/recent/SpecieServiceAsyncImpl.kt @@ -21,6 +21,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class SpecieServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : SpecieServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ChecklistServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ChecklistServiceAsync.kt index b197028..983897f 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ChecklistServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ChecklistServiceAsync.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.product.checklist.ChecklistViewResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ interface ChecklistServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ChecklistServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ChecklistServiceAsyncImpl.kt index 124f598..20a240c 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ChecklistServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ChecklistServiceAsyncImpl.kt @@ -21,6 +21,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ class ChecklistServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : ChecklistServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ListServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ListServiceAsync.kt index e97f814..c756752 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ListServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ListServiceAsync.kt @@ -11,6 +11,12 @@ import com.phoebe.api.services.async.product.lists.HistoricalServiceAsync import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface ListServiceAsync { /** @@ -25,6 +31,12 @@ interface ListServiceAsync { */ fun withOptions(modifier: Consumer): ListServiceAsync + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ fun historical(): HistoricalServiceAsync /** Get information on the most recently submitted checklists for a region. */ @@ -73,6 +85,12 @@ interface ListServiceAsync { */ fun withOptions(modifier: Consumer): ListServiceAsync.WithRawResponse + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ fun historical(): HistoricalServiceAsync.WithRawResponse /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ListServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ListServiceAsyncImpl.kt index 283a90c..59f2da7 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ListServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/ListServiceAsyncImpl.kt @@ -23,6 +23,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class ListServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : ListServiceAsync { @@ -39,6 +45,12 @@ class ListServiceAsyncImpl internal constructor(private val clientOptions: Clien override fun withOptions(modifier: Consumer): ListServiceAsync = ListServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ override fun historical(): HistoricalServiceAsync = historical override fun retrieve( @@ -65,6 +77,12 @@ class ListServiceAsyncImpl internal constructor(private val clientOptions: Clien clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ override fun historical(): HistoricalServiceAsync.WithRawResponse = historical private val retrieveHandler: Handler> = diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/SpeciesListServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/SpeciesListServiceAsync.kt index 3ec57ac..d26801d 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/SpeciesListServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/SpeciesListServiceAsync.kt @@ -9,6 +9,12 @@ import com.phoebe.api.models.product.specieslist.SpeciesListListParams import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ interface SpeciesListServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/SpeciesListServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/SpeciesListServiceAsyncImpl.kt index dc5158c..bfc93c4 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/SpeciesListServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/SpeciesListServiceAsyncImpl.kt @@ -20,6 +20,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ class SpeciesListServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : SpeciesListServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/StatServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/StatServiceAsync.kt index b5fdff5..7fdbd34 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/StatServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/StatServiceAsync.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.product.stats.StatRetrieveResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ interface StatServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/StatServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/StatServiceAsyncImpl.kt index 019bee6..eb418d7 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/StatServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/StatServiceAsyncImpl.kt @@ -21,6 +21,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ class StatServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : StatServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/Top100ServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/Top100ServiceAsync.kt index 5959cac..30c8b8b 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/Top100ServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/Top100ServiceAsync.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.product.top100.Top100RetrieveResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ interface Top100ServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/Top100ServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/Top100ServiceAsyncImpl.kt index ca37601..e1629e4 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/Top100ServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/Top100ServiceAsyncImpl.kt @@ -21,6 +21,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ class Top100ServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : Top100ServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/lists/HistoricalServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/lists/HistoricalServiceAsync.kt index eb57fdf..f90bd38 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/lists/HistoricalServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/lists/HistoricalServiceAsync.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.product.lists.historical.HistoricalRetrieveResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ interface HistoricalServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/lists/HistoricalServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/lists/HistoricalServiceAsyncImpl.kt index b73ad2e..e30a04c 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/lists/HistoricalServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/product/lists/HistoricalServiceAsyncImpl.kt @@ -21,6 +21,12 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ class HistoricalServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : HistoricalServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/HotspotServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/HotspotServiceAsync.kt index 3bd551d..22a0dcc 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/HotspotServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/HotspotServiceAsync.kt @@ -12,6 +12,10 @@ import com.phoebe.api.services.async.ref.hotspot.InfoServiceAsync import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ interface HotspotServiceAsync { /** @@ -26,8 +30,16 @@ interface HotspotServiceAsync { */ fun withOptions(modifier: Consumer): HotspotServiceAsync + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ fun geo(): GeoServiceAsync + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ fun info(): InfoServiceAsync /** Hotspots in a region */ @@ -80,8 +92,16 @@ interface HotspotServiceAsync { modifier: Consumer ): HotspotServiceAsync.WithRawResponse + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ fun geo(): GeoServiceAsync.WithRawResponse + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ fun info(): InfoServiceAsync.WithRawResponse /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/HotspotServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/HotspotServiceAsyncImpl.kt index d97a947..4b45528 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/HotspotServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/HotspotServiceAsyncImpl.kt @@ -25,6 +25,10 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ class HotspotServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : HotspotServiceAsync { @@ -41,8 +45,16 @@ class HotspotServiceAsyncImpl internal constructor(private val clientOptions: Cl override fun withOptions(modifier: Consumer): HotspotServiceAsync = HotspotServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ override fun geo(): GeoServiceAsync = geo + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ override fun info(): InfoServiceAsync = info override fun list( @@ -73,8 +85,16 @@ class HotspotServiceAsyncImpl internal constructor(private val clientOptions: Cl clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ override fun geo(): GeoServiceAsync.WithRawResponse = geo + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ override fun info(): InfoServiceAsync.WithRawResponse = info private val listHandler: Handler> = diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/RegionServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/RegionServiceAsync.kt index 0ea8b98..1a34d96 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/RegionServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/RegionServiceAsync.kt @@ -22,10 +22,13 @@ interface RegionServiceAsync { */ fun withOptions(modifier: Consumer): RegionServiceAsync + /** With the ref/geo end-point you can find a country's or region's neighbours. */ fun adjacent(): AdjacentServiceAsync + /** The ref/region end-points return information on regions. */ fun info(): InfoServiceAsync + /** The ref/region end-points return information on regions. */ fun list(): ListServiceAsync /** @@ -42,10 +45,13 @@ interface RegionServiceAsync { modifier: Consumer ): RegionServiceAsync.WithRawResponse + /** With the ref/geo end-point you can find a country's or region's neighbours. */ fun adjacent(): AdjacentServiceAsync.WithRawResponse + /** The ref/region end-points return information on regions. */ fun info(): InfoServiceAsync.WithRawResponse + /** The ref/region end-points return information on regions. */ fun list(): ListServiceAsync.WithRawResponse } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/RegionServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/RegionServiceAsyncImpl.kt index b0c90fa..9375f9f 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/RegionServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/RegionServiceAsyncImpl.kt @@ -29,10 +29,13 @@ class RegionServiceAsyncImpl internal constructor(private val clientOptions: Cli override fun withOptions(modifier: Consumer): RegionServiceAsync = RegionServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** With the ref/geo end-point you can find a country's or region's neighbours. */ override fun adjacent(): AdjacentServiceAsync = adjacent + /** The ref/region end-points return information on regions. */ override fun info(): InfoServiceAsync = info + /** The ref/region end-points return information on regions. */ override fun list(): ListServiceAsync = list class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -57,10 +60,13 @@ class RegionServiceAsyncImpl internal constructor(private val clientOptions: Cli clientOptions.toBuilder().apply(modifier::accept).build() ) + /** With the ref/geo end-point you can find a country's or region's neighbours. */ override fun adjacent(): AdjacentServiceAsync.WithRawResponse = adjacent + /** The ref/region end-points return information on regions. */ override fun info(): InfoServiceAsync.WithRawResponse = info + /** The ref/region end-points return information on regions. */ override fun list(): ListServiceAsync.WithRawResponse = list } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/GeoServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/GeoServiceAsync.kt index d8857b2..93d91bb 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/GeoServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/GeoServiceAsync.kt @@ -10,6 +10,10 @@ import com.phoebe.api.models.ref.hotspot.geo.GeoRetrieveResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ interface GeoServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/GeoServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/GeoServiceAsyncImpl.kt index 3f35e4f..8ae7341 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/GeoServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/GeoServiceAsyncImpl.kt @@ -19,6 +19,10 @@ import com.phoebe.api.models.ref.hotspot.geo.GeoRetrieveResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ class GeoServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : GeoServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/InfoServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/InfoServiceAsync.kt index 1d4298e..c9b0b4b 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/InfoServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/InfoServiceAsync.kt @@ -10,6 +10,10 @@ import com.phoebe.api.models.ref.hotspot.info.InfoRetrieveResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ interface InfoServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/InfoServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/InfoServiceAsyncImpl.kt index f62d734..987ca9a 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/InfoServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/hotspot/InfoServiceAsyncImpl.kt @@ -21,6 +21,10 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ class InfoServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : InfoServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/AdjacentServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/AdjacentServiceAsync.kt index 4dc99e5..5a5b38d 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/AdjacentServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/AdjacentServiceAsync.kt @@ -10,6 +10,7 @@ import com.phoebe.api.models.ref.region.adjacent.AdjacentListResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** With the ref/geo end-point you can find a country's or region's neighbours. */ interface AdjacentServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/AdjacentServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/AdjacentServiceAsyncImpl.kt index c5684f9..ef6fa5c 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/AdjacentServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/AdjacentServiceAsyncImpl.kt @@ -21,6 +21,7 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** With the ref/geo end-point you can find a country's or region's neighbours. */ class AdjacentServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : AdjacentServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/InfoServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/InfoServiceAsync.kt index a50fb67..c7d961a 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/InfoServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/InfoServiceAsync.kt @@ -10,6 +10,7 @@ import com.phoebe.api.models.ref.region.info.InfoRetrieveResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** The ref/region end-points return information on regions. */ interface InfoServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/InfoServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/InfoServiceAsyncImpl.kt index e4adb67..8167b15 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/InfoServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/InfoServiceAsyncImpl.kt @@ -21,6 +21,7 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** The ref/region end-points return information on regions. */ class InfoServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : InfoServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/ListServiceAsync.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/ListServiceAsync.kt index 75b7a3b..ba87750 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/ListServiceAsync.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/ListServiceAsync.kt @@ -10,6 +10,7 @@ import com.phoebe.api.models.ref.region.list.ListListResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +/** The ref/region end-points return information on regions. */ interface ListServiceAsync { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/ListServiceAsyncImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/ListServiceAsyncImpl.kt index 0c4a8fb..6e074a9 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/ListServiceAsyncImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/async/ref/region/ListServiceAsyncImpl.kt @@ -21,6 +21,7 @@ import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** The ref/region end-points return information on regions. */ class ListServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : ListServiceAsync { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ProductService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ProductService.kt index f2d20da..2ac82b7 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ProductService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ProductService.kt @@ -24,14 +24,45 @@ interface ProductService { */ fun withOptions(modifier: Consumer): ProductService + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun lists(): ListService + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ fun top100(): Top100Service + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ fun stats(): StatService + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ fun speciesList(): SpeciesListService + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ fun checklist(): ChecklistService /** A view of [ProductService] that provides access to raw HTTP responses for each method. */ @@ -44,14 +75,45 @@ interface ProductService { */ fun withOptions(modifier: Consumer): ProductService.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun lists(): ListService.WithRawResponse + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ fun top100(): Top100Service.WithRawResponse + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ fun stats(): StatService.WithRawResponse + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ fun speciesList(): SpeciesListService.WithRawResponse + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ fun checklist(): ChecklistService.WithRawResponse } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ProductServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ProductServiceImpl.kt index b58b4fa..c4d3a4f 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ProductServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ProductServiceImpl.kt @@ -37,14 +37,45 @@ class ProductServiceImpl internal constructor(private val clientOptions: ClientO override fun withOptions(modifier: Consumer): ProductService = ProductServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun lists(): ListService = lists + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ override fun top100(): Top100Service = top100 + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ override fun stats(): StatService = stats + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ override fun speciesList(): SpeciesListService = speciesList + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ override fun checklist(): ChecklistService = checklist class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -77,14 +108,45 @@ class ProductServiceImpl internal constructor(private val clientOptions: ClientO clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun lists(): ListService.WithRawResponse = lists + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ override fun top100(): Top100Service.WithRawResponse = top100 + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ override fun stats(): StatService.WithRawResponse = stats + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ override fun speciesList(): SpeciesListService.WithRawResponse = speciesList + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ override fun checklist(): ChecklistService.WithRawResponse = checklist } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/RefService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/RefService.kt index c75b3dc..fa98695 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/RefService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/RefService.kt @@ -24,6 +24,10 @@ interface RefService { fun region(): RegionService + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ fun hotspot(): HotspotService fun taxonomy(): TaxonomyService @@ -40,6 +44,10 @@ interface RefService { fun region(): RegionService.WithRawResponse + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ fun hotspot(): HotspotService.WithRawResponse fun taxonomy(): TaxonomyService.WithRawResponse diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/RefServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/RefServiceImpl.kt index d354442..9b7f9dc 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/RefServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/RefServiceImpl.kt @@ -30,6 +30,10 @@ class RefServiceImpl internal constructor(private val clientOptions: ClientOptio override fun region(): RegionService = region + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ override fun hotspot(): HotspotService = hotspot override fun taxonomy(): TaxonomyService = taxonomy @@ -58,6 +62,10 @@ class RefServiceImpl internal constructor(private val clientOptions: ClientOptio override fun region(): RegionService.WithRawResponse = region + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ override fun hotspot(): HotspotService.WithRawResponse = hotspot override fun taxonomy(): TaxonomyService.WithRawResponse = taxonomy diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/ObservationService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/ObservationService.kt index 1278cce..cae2b55 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/ObservationService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/ObservationService.kt @@ -22,6 +22,13 @@ interface ObservationService { */ fun withOptions(modifier: Consumer): ObservationService + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun recent(): RecentService fun geo(): GeoService @@ -42,6 +49,13 @@ interface ObservationService { modifier: Consumer ): ObservationService.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun recent(): RecentService.WithRawResponse fun geo(): GeoService.WithRawResponse diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/ObservationServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/ObservationServiceImpl.kt index f35d196..bb235c5 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/ObservationServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/ObservationServiceImpl.kt @@ -29,6 +29,13 @@ class ObservationServiceImpl internal constructor(private val clientOptions: Cli override fun withOptions(modifier: Consumer): ObservationService = ObservationServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun recent(): RecentService = recent override fun geo(): GeoService = geo @@ -57,6 +64,13 @@ class ObservationServiceImpl internal constructor(private val clientOptions: Cli clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun recent(): RecentService.WithRawResponse = recent override fun geo(): GeoService.WithRawResponse = geo diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/GeoService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/GeoService.kt index 78ee7d1..d8470e6 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/GeoService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/GeoService.kt @@ -20,6 +20,13 @@ interface GeoService { */ fun withOptions(modifier: Consumer): GeoService + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun recent(): RecentService /** A view of [GeoService] that provides access to raw HTTP responses for each method. */ @@ -32,6 +39,13 @@ interface GeoService { */ fun withOptions(modifier: Consumer): GeoService.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun recent(): RecentService.WithRawResponse } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/GeoServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/GeoServiceImpl.kt index c3aca8e..e018b35 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/GeoServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/GeoServiceImpl.kt @@ -20,6 +20,13 @@ class GeoServiceImpl internal constructor(private val clientOptions: ClientOptio override fun withOptions(modifier: Consumer): GeoService = GeoServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun recent(): RecentService = recent class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -36,6 +43,13 @@ class GeoServiceImpl internal constructor(private val clientOptions: ClientOptio clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun recent(): RecentService.WithRawResponse = recent } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/NearestService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/NearestService.kt index 2636358..ee7bdcb 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/NearestService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/NearestService.kt @@ -20,6 +20,13 @@ interface NearestService { */ fun withOptions(modifier: Consumer): NearestService + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun geoSpecies(): GeoSpecieService /** A view of [NearestService] that provides access to raw HTTP responses for each method. */ @@ -32,6 +39,13 @@ interface NearestService { */ fun withOptions(modifier: Consumer): NearestService.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun geoSpecies(): GeoSpecieService.WithRawResponse } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/NearestServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/NearestServiceImpl.kt index ce3c568..7a33860 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/NearestServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/NearestServiceImpl.kt @@ -21,6 +21,13 @@ class NearestServiceImpl internal constructor(private val clientOptions: ClientO override fun withOptions(modifier: Consumer): NearestService = NearestServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun geoSpecies(): GeoSpecieService = geoSpecies class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -37,6 +44,13 @@ class NearestServiceImpl internal constructor(private val clientOptions: ClientO clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun geoSpecies(): GeoSpecieService.WithRawResponse = geoSpecies } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/RecentService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/RecentService.kt index 6730ebe..5c71036 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/RecentService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/RecentService.kt @@ -13,6 +13,12 @@ import com.phoebe.api.services.blocking.data.observations.recent.NotableService import com.phoebe.api.services.blocking.data.observations.recent.SpecieService import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface RecentService { /** @@ -27,10 +33,31 @@ interface RecentService { */ fun withOptions(modifier: Consumer): RecentService + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun notable(): NotableService + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun species(): SpecieService + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun historic(): HistoricService /** @@ -76,10 +103,31 @@ interface RecentService { */ fun withOptions(modifier: Consumer): RecentService.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun notable(): NotableService.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun species(): SpecieService.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun historic(): HistoricService.WithRawResponse /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/RecentServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/RecentServiceImpl.kt index e6dd3bc..27417b2 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/RecentServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/RecentServiceImpl.kt @@ -26,6 +26,12 @@ import com.phoebe.api.services.blocking.data.observations.recent.SpecieServiceIm import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class RecentServiceImpl internal constructor(private val clientOptions: ClientOptions) : RecentService { @@ -44,10 +50,31 @@ class RecentServiceImpl internal constructor(private val clientOptions: ClientOp override fun withOptions(modifier: Consumer): RecentService = RecentServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun notable(): NotableService = notable + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun species(): SpecieService = species + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun historic(): HistoricService = historic override fun list(params: RecentListParams, requestOptions: RequestOptions): List = @@ -79,10 +106,31 @@ class RecentServiceImpl internal constructor(private val clientOptions: ClientOp clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun notable(): NotableService.WithRawResponse = notable + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun species(): SpecieService.WithRawResponse = species + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun historic(): HistoricService.WithRawResponse = historic private val listHandler: Handler> = diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/RecentService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/RecentService.kt index 01fdd91..01499e6 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/RecentService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/RecentService.kt @@ -12,6 +12,12 @@ import com.phoebe.api.services.blocking.data.observations.geo.recent.NotableServ import com.phoebe.api.services.blocking.data.observations.geo.recent.SpecieService import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface RecentService { /** @@ -26,8 +32,22 @@ interface RecentService { */ fun withOptions(modifier: Consumer): RecentService + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun species(): SpecieService + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ fun notable(): NotableService /** @@ -53,8 +73,22 @@ interface RecentService { */ fun withOptions(modifier: Consumer): RecentService.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun species(): SpecieService.WithRawResponse + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ fun notable(): NotableService.WithRawResponse /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/RecentServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/RecentServiceImpl.kt index ff0af93..7206e7b 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/RecentServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/RecentServiceImpl.kt @@ -22,6 +22,12 @@ import com.phoebe.api.services.blocking.data.observations.geo.recent.SpecieServi import com.phoebe.api.services.blocking.data.observations.geo.recent.SpecieServiceImpl import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class RecentServiceImpl internal constructor(private val clientOptions: ClientOptions) : RecentService { @@ -38,8 +44,22 @@ class RecentServiceImpl internal constructor(private val clientOptions: ClientOp override fun withOptions(modifier: Consumer): RecentService = RecentServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun species(): SpecieService = species + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, region + * or location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each + * end-point supports optional query parameters which allow you to filter the list of + * observations returned. + */ override fun notable(): NotableService = notable override fun list(params: RecentListParams, requestOptions: RequestOptions): List = @@ -67,8 +87,22 @@ class RecentServiceImpl internal constructor(private val clientOptions: ClientOp clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun species(): SpecieService.WithRawResponse = species + /** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. + * There are two categories of end-point: 1. Fetch observations for a specific country, + * region or location. 2. Fetch observations for nearby locations - up to a distance of + * 50km. Each end-point supports optional query parameters which allow you to filter the + * list of observations returned. + */ override fun notable(): NotableService.WithRawResponse = notable private val listHandler: Handler> = diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/NotableService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/NotableService.kt index ec04886..8b5a510 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/NotableService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/NotableService.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.Observation import com.phoebe.api.models.data.observations.geo.recent.notable.NotableListParams import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface NotableService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/NotableServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/NotableServiceImpl.kt index ccd5d57..9dd0a4d 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/NotableServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/NotableServiceImpl.kt @@ -18,6 +18,12 @@ import com.phoebe.api.models.data.observations.Observation import com.phoebe.api.models.data.observations.geo.recent.notable.NotableListParams import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class NotableServiceImpl internal constructor(private val clientOptions: ClientOptions) : NotableService { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/SpecieService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/SpecieService.kt index f8aa22e..759a2c3 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/SpecieService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/SpecieService.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.Observation import com.phoebe.api.models.data.observations.geo.recent.species.SpecieListParams import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface SpecieService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/SpecieServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/SpecieServiceImpl.kt index eb2ba29..1461034 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/SpecieServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/geo/recent/SpecieServiceImpl.kt @@ -20,6 +20,12 @@ import com.phoebe.api.models.data.observations.geo.recent.species.SpecieListPara import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class SpecieServiceImpl internal constructor(private val clientOptions: ClientOptions) : SpecieService { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/nearest/GeoSpecieService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/nearest/GeoSpecieService.kt index a1ace2d..e06a9b0 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/nearest/GeoSpecieService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/nearest/GeoSpecieService.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.Observation import com.phoebe.api.models.data.observations.nearest.geospecies.GeoSpecieListParams import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface GeoSpecieService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/nearest/GeoSpecieServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/nearest/GeoSpecieServiceImpl.kt index 6c5df31..c8c1567 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/nearest/GeoSpecieServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/nearest/GeoSpecieServiceImpl.kt @@ -20,6 +20,12 @@ import com.phoebe.api.models.data.observations.nearest.geospecies.GeoSpecieListP import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class GeoSpecieServiceImpl internal constructor(private val clientOptions: ClientOptions) : GeoSpecieService { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/HistoricService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/HistoricService.kt index bea6961..a393c7d 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/HistoricService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/HistoricService.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.Observation import com.phoebe.api.models.data.observations.recent.historic.HistoricListParams import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface HistoricService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/HistoricServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/HistoricServiceImpl.kt index 2ab0d8d..1827d8f 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/HistoricServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/HistoricServiceImpl.kt @@ -20,6 +20,12 @@ import com.phoebe.api.models.data.observations.recent.historic.HistoricListParam import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class HistoricServiceImpl internal constructor(private val clientOptions: ClientOptions) : HistoricService { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/NotableService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/NotableService.kt index 8ba3c6b..f8d1255 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/NotableService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/NotableService.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.Observation import com.phoebe.api.models.data.observations.recent.notable.NotableListParams import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface NotableService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/NotableServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/NotableServiceImpl.kt index 5635eba..5167394 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/NotableServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/NotableServiceImpl.kt @@ -20,6 +20,12 @@ import com.phoebe.api.models.data.observations.recent.notable.NotableListParams import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class NotableServiceImpl internal constructor(private val clientOptions: ClientOptions) : NotableService { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/SpecieService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/SpecieService.kt index 5c62082..af97b53 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/SpecieService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/SpecieService.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.data.observations.Observation import com.phoebe.api.models.data.observations.recent.species.SpecieRetrieveParams import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface SpecieService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/SpecieServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/SpecieServiceImpl.kt index 34e2152..8341abe 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/SpecieServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/data/observations/recent/SpecieServiceImpl.kt @@ -20,6 +20,12 @@ import com.phoebe.api.models.data.observations.recent.species.SpecieRetrievePara import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class SpecieServiceImpl internal constructor(private val clientOptions: ClientOptions) : SpecieService { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ChecklistService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ChecklistService.kt index a988775..93d51eb 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ChecklistService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ChecklistService.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.product.checklist.ChecklistViewParams import com.phoebe.api.models.product.checklist.ChecklistViewResponse import java.util.function.Consumer +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ interface ChecklistService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ChecklistServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ChecklistServiceImpl.kt index 2172651..1c72ff0 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ChecklistServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ChecklistServiceImpl.kt @@ -20,6 +20,12 @@ import com.phoebe.api.models.product.checklist.ChecklistViewResponse import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ class ChecklistServiceImpl internal constructor(private val clientOptions: ClientOptions) : ChecklistService { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ListService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ListService.kt index b18292f..5953c11 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ListService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ListService.kt @@ -11,6 +11,12 @@ import com.phoebe.api.models.product.lists.ListRetrieveResponse import com.phoebe.api.services.blocking.product.lists.HistoricalService import java.util.function.Consumer +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ interface ListService { /** @@ -25,6 +31,12 @@ interface ListService { */ fun withOptions(modifier: Consumer): ListService + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ fun historical(): HistoricalService /** Get information on the most recently submitted checklists for a region. */ @@ -69,6 +81,12 @@ interface ListService { */ fun withOptions(modifier: Consumer): ListService.WithRawResponse + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ fun historical(): HistoricalService.WithRawResponse /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ListServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ListServiceImpl.kt index 9b3f5b8..34e998b 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ListServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/ListServiceImpl.kt @@ -22,6 +22,12 @@ import com.phoebe.api.services.blocking.product.lists.HistoricalServiceImpl import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The data/obs end-points are used to fetch observations submitted to eBird in checklists. There + * are two categories of end-point: 1. Fetch observations for a specific country, region or + * location. 2. Fetch observations for nearby locations - up to a distance of 50km. Each end-point + * supports optional query parameters which allow you to filter the list of observations returned. + */ class ListServiceImpl internal constructor(private val clientOptions: ClientOptions) : ListService { private val withRawResponse: ListService.WithRawResponse by lazy { @@ -35,6 +41,12 @@ class ListServiceImpl internal constructor(private val clientOptions: ClientOpti override fun withOptions(modifier: Consumer): ListService = ListServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a + * given date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted + * on a given date. 5. The details and all the observations of a checklist. + */ override fun historical(): HistoricalService = historical override fun retrieve( @@ -61,6 +73,12 @@ class ListServiceImpl internal constructor(private val clientOptions: ClientOpti clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * The product end-points make it easy to get the information shown in various pages on the + * eBird web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted + * on a given date. 3. The most recent checklists submitted. 4. A summary of the checklists + * submitted on a given date. 5. The details and all the observations of a checklist. + */ override fun historical(): HistoricalService.WithRawResponse = historical private val retrieveHandler: Handler> = diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/SpeciesListService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/SpeciesListService.kt index 932b280..98c4361 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/SpeciesListService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/SpeciesListService.kt @@ -9,6 +9,12 @@ import com.phoebe.api.core.http.HttpResponseFor import com.phoebe.api.models.product.specieslist.SpeciesListListParams import java.util.function.Consumer +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ interface SpeciesListService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/SpeciesListServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/SpeciesListServiceImpl.kt index 8611084..b4a8ab6 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/SpeciesListServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/SpeciesListServiceImpl.kt @@ -19,6 +19,12 @@ import com.phoebe.api.models.product.specieslist.SpeciesListListParams import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ class SpeciesListServiceImpl internal constructor(private val clientOptions: ClientOptions) : SpeciesListService { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/StatService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/StatService.kt index e2e4a90..0dfc96c 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/StatService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/StatService.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.product.stats.StatRetrieveParams import com.phoebe.api.models.product.stats.StatRetrieveResponse import java.util.function.Consumer +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ interface StatService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/StatServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/StatServiceImpl.kt index 956dcce..6019a01 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/StatServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/StatServiceImpl.kt @@ -20,6 +20,12 @@ import com.phoebe.api.models.product.stats.StatRetrieveResponse import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ class StatServiceImpl internal constructor(private val clientOptions: ClientOptions) : StatService { private val withRawResponse: StatService.WithRawResponse by lazy { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/Top100Service.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/Top100Service.kt index 3bd3264..9bf8037 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/Top100Service.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/Top100Service.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.product.top100.Top100RetrieveParams import com.phoebe.api.models.product.top100.Top100RetrieveResponse import java.util.function.Consumer +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ interface Top100Service { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/Top100ServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/Top100ServiceImpl.kt index 82d0609..61b9f65 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/Top100ServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/Top100ServiceImpl.kt @@ -20,6 +20,12 @@ import com.phoebe.api.models.product.top100.Top100RetrieveResponse import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ class Top100ServiceImpl internal constructor(private val clientOptions: ClientOptions) : Top100Service { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/lists/HistoricalService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/lists/HistoricalService.kt index 7112189..63d7444 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/lists/HistoricalService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/lists/HistoricalService.kt @@ -10,6 +10,12 @@ import com.phoebe.api.models.product.lists.historical.HistoricalRetrieveParams import com.phoebe.api.models.product.lists.historical.HistoricalRetrieveResponse import java.util.function.Consumer +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ interface HistoricalService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/lists/HistoricalServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/lists/HistoricalServiceImpl.kt index 5b26b43..b051069 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/lists/HistoricalServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/product/lists/HistoricalServiceImpl.kt @@ -20,6 +20,12 @@ import com.phoebe.api.models.product.lists.historical.HistoricalRetrieveResponse import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * The product end-points make it easy to get the information shown in various pages on the eBird + * web site: 1. The Top 100 contributors on a given date. 2. The checklists submitted on a given + * date. 3. The most recent checklists submitted. 4. A summary of the checklists submitted on a + * given date. 5. The details and all the observations of a checklist. + */ class HistoricalServiceImpl internal constructor(private val clientOptions: ClientOptions) : HistoricalService { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/HotspotService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/HotspotService.kt index 0a68817..9e02aad 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/HotspotService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/HotspotService.kt @@ -12,6 +12,10 @@ import com.phoebe.api.services.blocking.ref.hotspot.GeoService import com.phoebe.api.services.blocking.ref.hotspot.InfoService import java.util.function.Consumer +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ interface HotspotService { /** @@ -26,8 +30,16 @@ interface HotspotService { */ fun withOptions(modifier: Consumer): HotspotService + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ fun geo(): GeoService + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ fun info(): InfoService /** Hotspots in a region */ @@ -72,8 +84,16 @@ interface HotspotService { */ fun withOptions(modifier: Consumer): HotspotService.WithRawResponse + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ fun geo(): GeoService.WithRawResponse + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ fun info(): InfoService.WithRawResponse /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/HotspotServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/HotspotServiceImpl.kt index 134bc1b..c751131 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/HotspotServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/HotspotServiceImpl.kt @@ -24,6 +24,10 @@ import com.phoebe.api.services.blocking.ref.hotspot.InfoServiceImpl import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ class HotspotServiceImpl internal constructor(private val clientOptions: ClientOptions) : HotspotService { @@ -40,8 +44,16 @@ class HotspotServiceImpl internal constructor(private val clientOptions: ClientO override fun withOptions(modifier: Consumer): HotspotService = HotspotServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ override fun geo(): GeoService = geo + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or + * nearby hotspots + */ override fun info(): InfoService = info override fun list( @@ -72,8 +84,16 @@ class HotspotServiceImpl internal constructor(private val clientOptions: ClientO clientOptions.toBuilder().apply(modifier::accept).build() ) + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ override fun geo(): GeoService.WithRawResponse = geo + /** + * With the ref/hotspot end-points you can find the hotspots for a given country or region + * or nearby hotspots + */ override fun info(): InfoService.WithRawResponse = info private val listHandler: Handler> = diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/RegionService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/RegionService.kt index 2bdc649..36bfdfc 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/RegionService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/RegionService.kt @@ -22,10 +22,13 @@ interface RegionService { */ fun withOptions(modifier: Consumer): RegionService + /** With the ref/geo end-point you can find a country's or region's neighbours. */ fun adjacent(): AdjacentService + /** The ref/region end-points return information on regions. */ fun info(): InfoService + /** The ref/region end-points return information on regions. */ fun list(): ListService /** A view of [RegionService] that provides access to raw HTTP responses for each method. */ @@ -38,10 +41,13 @@ interface RegionService { */ fun withOptions(modifier: Consumer): RegionService.WithRawResponse + /** With the ref/geo end-point you can find a country's or region's neighbours. */ fun adjacent(): AdjacentService.WithRawResponse + /** The ref/region end-points return information on regions. */ fun info(): InfoService.WithRawResponse + /** The ref/region end-points return information on regions. */ fun list(): ListService.WithRawResponse } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/RegionServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/RegionServiceImpl.kt index 7ab18f2..7a9b448 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/RegionServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/RegionServiceImpl.kt @@ -29,10 +29,13 @@ class RegionServiceImpl internal constructor(private val clientOptions: ClientOp override fun withOptions(modifier: Consumer): RegionService = RegionServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + /** With the ref/geo end-point you can find a country's or region's neighbours. */ override fun adjacent(): AdjacentService = adjacent + /** The ref/region end-points return information on regions. */ override fun info(): InfoService = info + /** The ref/region end-points return information on regions. */ override fun list(): ListService = list class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -57,10 +60,13 @@ class RegionServiceImpl internal constructor(private val clientOptions: ClientOp clientOptions.toBuilder().apply(modifier::accept).build() ) + /** With the ref/geo end-point you can find a country's or region's neighbours. */ override fun adjacent(): AdjacentService.WithRawResponse = adjacent + /** The ref/region end-points return information on regions. */ override fun info(): InfoService.WithRawResponse = info + /** The ref/region end-points return information on regions. */ override fun list(): ListService.WithRawResponse = list } } diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/GeoService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/GeoService.kt index 9d8f56d..aa97b60 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/GeoService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/GeoService.kt @@ -10,6 +10,10 @@ import com.phoebe.api.models.ref.hotspot.geo.GeoRetrieveParams import com.phoebe.api.models.ref.hotspot.geo.GeoRetrieveResponse import java.util.function.Consumer +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ interface GeoService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/GeoServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/GeoServiceImpl.kt index 8781a46..64bcdae 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/GeoServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/GeoServiceImpl.kt @@ -18,6 +18,10 @@ import com.phoebe.api.models.ref.hotspot.geo.GeoRetrieveParams import com.phoebe.api.models.ref.hotspot.geo.GeoRetrieveResponse import java.util.function.Consumer +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ class GeoServiceImpl internal constructor(private val clientOptions: ClientOptions) : GeoService { private val withRawResponse: GeoService.WithRawResponse by lazy { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/InfoService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/InfoService.kt index 806217c..362798b 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/InfoService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/InfoService.kt @@ -10,6 +10,10 @@ import com.phoebe.api.models.ref.hotspot.info.InfoRetrieveParams import com.phoebe.api.models.ref.hotspot.info.InfoRetrieveResponse import java.util.function.Consumer +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ interface InfoService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/InfoServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/InfoServiceImpl.kt index ca1439f..c8d8059 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/InfoServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/hotspot/InfoServiceImpl.kt @@ -20,6 +20,10 @@ import com.phoebe.api.models.ref.hotspot.info.InfoRetrieveResponse import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** + * With the ref/hotspot end-points you can find the hotspots for a given country or region or nearby + * hotspots + */ class InfoServiceImpl internal constructor(private val clientOptions: ClientOptions) : InfoService { private val withRawResponse: InfoService.WithRawResponse by lazy { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/AdjacentService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/AdjacentService.kt index 16e76a2..cbb0755 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/AdjacentService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/AdjacentService.kt @@ -10,6 +10,7 @@ import com.phoebe.api.models.ref.region.adjacent.AdjacentListParams import com.phoebe.api.models.ref.region.adjacent.AdjacentListResponse import java.util.function.Consumer +/** With the ref/geo end-point you can find a country's or region's neighbours. */ interface AdjacentService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/AdjacentServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/AdjacentServiceImpl.kt index 1bfcdcd..fa18ea2 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/AdjacentServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/AdjacentServiceImpl.kt @@ -20,6 +20,7 @@ import com.phoebe.api.models.ref.region.adjacent.AdjacentListResponse import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** With the ref/geo end-point you can find a country's or region's neighbours. */ class AdjacentServiceImpl internal constructor(private val clientOptions: ClientOptions) : AdjacentService { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/InfoService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/InfoService.kt index e2b2af2..2073cd2 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/InfoService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/InfoService.kt @@ -10,6 +10,7 @@ import com.phoebe.api.models.ref.region.info.InfoRetrieveParams import com.phoebe.api.models.ref.region.info.InfoRetrieveResponse import java.util.function.Consumer +/** The ref/region end-points return information on regions. */ interface InfoService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/InfoServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/InfoServiceImpl.kt index 13a687d..15c13e7 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/InfoServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/InfoServiceImpl.kt @@ -20,6 +20,7 @@ import com.phoebe.api.models.ref.region.info.InfoRetrieveResponse import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** The ref/region end-points return information on regions. */ class InfoServiceImpl internal constructor(private val clientOptions: ClientOptions) : InfoService { private val withRawResponse: InfoService.WithRawResponse by lazy { diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/ListService.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/ListService.kt index 05f61ec..67dcf61 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/ListService.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/ListService.kt @@ -10,6 +10,7 @@ import com.phoebe.api.models.ref.region.list.ListListParams import com.phoebe.api.models.ref.region.list.ListListResponse import java.util.function.Consumer +/** The ref/region end-points return information on regions. */ interface ListService { /** diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/ListServiceImpl.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/ListServiceImpl.kt index 01ff6b1..d507791 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/ListServiceImpl.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/services/blocking/ref/region/ListServiceImpl.kt @@ -20,6 +20,7 @@ import com.phoebe.api.models.ref.region.list.ListListResponse import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull +/** The ref/region end-points return information on regions. */ class ListServiceImpl internal constructor(private val clientOptions: ClientOptions) : ListService { private val withRawResponse: ListService.WithRawResponse by lazy { From ea5500a64b0688e57f2ca9f3dee0eaaa74d9f860 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:37:55 +0000 Subject: [PATCH 30/41] chore(internal): codegen related update --- buildSrc/src/main/kotlin/phoebe.java.gradle.kts | 2 +- .../com/phoebe/api/core/http/RetryingHttpClient.kt | 9 ++------- scripts/mock | 13 ++++++++++++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/buildSrc/src/main/kotlin/phoebe.java.gradle.kts b/buildSrc/src/main/kotlin/phoebe.java.gradle.kts index 81d5d32..a3cfe28 100644 --- a/buildSrc/src/main/kotlin/phoebe.java.gradle.kts +++ b/buildSrc/src/main/kotlin/phoebe.java.gradle.kts @@ -54,7 +54,7 @@ tasks.withType().configureEach { val palantir by configurations.creating dependencies { - palantir("com.palantir.javaformat:palantir-java-format:2.73.0") + palantir("com.palantir.javaformat:palantir-java-format:2.89.0") } fun registerPalantir( diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt index e573807..06ed538 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt @@ -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/scripts/mock b/scripts/mock index 0b28f6e..bcf3b39 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,11 +21,22 @@ echo "==> Starting mock server with URL ${URL}" # Run prism mock on the given spec if [ "$1" == "--daemon" ]; then + # Pre-install the package so the download doesn't eat into the startup timeout + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & - # Wait for server to come online + # Wait for server to come online (max 30s) echo -n "Waiting for server" + attempts=0 while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + attempts=$((attempts + 1)) + if [ "$attempts" -ge 300 ]; then + echo + echo "Timed out waiting for Prism server to start" + cat .prism.log + exit 1 + fi echo -n "." sleep 0.1 done From 5945140f250d2b0ae6c2d9cd3fc3ee386a65ffc8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 7 Mar 2026 19:42:49 +0000 Subject: [PATCH 31/41] chore(ci): skip uploading artifacts on stainless-internal branches --- .github/workflows/ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2208be4..e28263d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,14 +65,18 @@ jobs: run: ./scripts/build - name: Get GitHub OIDC Token - if: github.repository == 'stainless-sdks/phoebe-java' + if: |- + github.repository == 'stainless-sdks/phoebe-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/phoebe-java' + if: |- + github.repository == 'stainless-sdks/phoebe-java' && + !startsWith(github.ref, 'refs/heads/stl/') env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} From 102eb54ea114aa3741df602701d022c2bf7f038f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:21:45 +0000 Subject: [PATCH 32/41] chore(internal): codegen related update --- .../api/core/http/RetryingHttpClient.kt | 2 +- .../api/core/http/RetryingHttpClientTest.kt | 224 +++++++++++++++--- 2 files changed, 192 insertions(+), 34 deletions(-) diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt index 06ed538..362969b 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/http/RetryingHttpClient.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/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, diff --git a/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt index 6579be5..cd79e0f 100644 --- a/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt +++ b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt @@ -20,7 +20,11 @@ import com.phoebe.api.core.RequestOptions import com.phoebe.api.core.Sleeper import com.phoebe.api.errors.PhoebeRetryableException import java.io.InputStream +import java.time.Clock import java.time.Duration +import java.time.OffsetDateTime +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter import java.util.concurrent.CompletableFuture import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach @@ -36,6 +40,21 @@ internal class RetryingHttpClientTest { private lateinit var baseUrl: String private lateinit var httpClient: HttpClient + private class RecordingSleeper : Sleeper { + val durations = mutableListOf() + + override fun sleep(duration: Duration) { + durations.add(duration) + } + + override fun sleepAsync(duration: Duration): CompletableFuture { + durations.add(duration) + return CompletableFuture.completedFuture(null) + } + + override fun close() {} + } + @BeforeEach fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { baseUrl = wmRuntimeInfo.httpBaseUrl @@ -86,7 +105,8 @@ internal class RetryingHttpClientTest { @ValueSource(booleans = [false, true]) fun execute(async: Boolean) { stubFor(post(urlPathEqualTo("/something")).willReturn(ok())) - val retryingClient = retryingHttpClientBuilder().build() + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).build() val response = retryingClient.execute( @@ -100,6 +120,7 @@ internal class RetryingHttpClientTest { assertThat(response.statusCode()).isEqualTo(200) verify(1, postRequestedFor(urlPathEqualTo("/something"))) + assertThat(sleeper.durations).isEmpty() assertNoResponseLeaks() } @@ -111,8 +132,12 @@ internal class RetryingHttpClientTest { .withHeader("X-Some-Header", matching("stainless-java-retry-.+")) .willReturn(ok()) ) + val sleeper = RecordingSleeper() val retryingClient = - retryingHttpClientBuilder().maxRetries(2).idempotencyHeader("X-Some-Header").build() + retryingHttpClientBuilder(sleeper) + .maxRetries(2) + .idempotencyHeader("X-Some-Header") + .build() val response = retryingClient.execute( @@ -126,20 +151,20 @@ internal class RetryingHttpClientTest { assertThat(response.statusCode()).isEqualTo(200) verify(1, postRequestedFor(urlPathEqualTo("/something"))) + assertThat(sleeper.durations).isEmpty() assertNoResponseLeaks() } @ParameterizedTest @ValueSource(booleans = [false, true]) fun execute_withRetryAfterHeader(async: Boolean) { + val retryAfterDate = "Wed, 21 Oct 2015 07:28:00 GMT" stubFor( post(urlPathEqualTo("/something")) // First we fail with a retry after header given as a date .inScenario("foo") .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - serviceUnavailable().withHeader("Retry-After", "Wed, 21 Oct 2015 07:28:00 GMT") - ) + .willReturn(serviceUnavailable().withHeader("Retry-After", retryAfterDate)) .willSetStateTo("RETRY_AFTER_DATE") ) stubFor( @@ -158,7 +183,13 @@ internal class RetryingHttpClientTest { .willReturn(ok()) .willSetStateTo("COMPLETED") ) - val retryingClient = retryingHttpClientBuilder().maxRetries(2).build() + // Fix the clock to 5 seconds before the Retry-After date so the date-based backoff is + // deterministic. + val retryAfterDateTime = + OffsetDateTime.parse(retryAfterDate, DateTimeFormatter.RFC_1123_DATE_TIME) + val clock = Clock.fixed(retryAfterDateTime.minusSeconds(5).toInstant(), ZoneOffset.UTC) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper, clock).maxRetries(2).build() val response = retryingClient.execute( @@ -186,19 +217,20 @@ internal class RetryingHttpClientTest { postRequestedFor(urlPathEqualTo("/something")) .withHeader("x-stainless-retry-count", equalTo("2")), ) + assertThat(sleeper.durations) + .containsExactly(Duration.ofSeconds(5), Duration.ofMillis(1234)) assertNoResponseLeaks() } @ParameterizedTest @ValueSource(booleans = [false, true]) fun execute_withOverwrittenRetryCountHeader(async: Boolean) { + val retryAfterDate = "Wed, 21 Oct 2015 07:28:00 GMT" stubFor( post(urlPathEqualTo("/something")) .inScenario("foo") // first we fail with a retry after header given as a date .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - serviceUnavailable().withHeader("Retry-After", "Wed, 21 Oct 2015 07:28:00 GMT") - ) + .willReturn(serviceUnavailable().withHeader("Retry-After", retryAfterDate)) .willSetStateTo("RETRY_AFTER_DATE") ) stubFor( @@ -208,7 +240,11 @@ internal class RetryingHttpClientTest { .willReturn(ok()) .willSetStateTo("COMPLETED") ) - val retryingClient = retryingHttpClientBuilder().maxRetries(2).build() + val retryAfterDateTime = + OffsetDateTime.parse(retryAfterDate, DateTimeFormatter.RFC_1123_DATE_TIME) + val clock = Clock.fixed(retryAfterDateTime.minusSeconds(5).toInstant(), ZoneOffset.UTC) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper, clock).maxRetries(2).build() val response = retryingClient.execute( @@ -227,6 +263,7 @@ internal class RetryingHttpClientTest { postRequestedFor(urlPathEqualTo("/something")) .withHeader("x-stainless-retry-count", equalTo("42")), ) + assertThat(sleeper.durations).containsExactly(Duration.ofSeconds(5)) assertNoResponseLeaks() } @@ -247,7 +284,8 @@ internal class RetryingHttpClientTest { .willReturn(ok()) .willSetStateTo("COMPLETED") ) - val retryingClient = retryingHttpClientBuilder().maxRetries(1).build() + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).maxRetries(1).build() val response = retryingClient.execute( @@ -261,6 +299,7 @@ internal class RetryingHttpClientTest { assertThat(response.statusCode()).isEqualTo(200) verify(2, postRequestedFor(urlPathEqualTo("/something"))) + assertThat(sleeper.durations).containsExactly(Duration.ofMillis(10)) assertNoResponseLeaks() } @@ -301,21 +340,12 @@ internal class RetryingHttpClientTest { override fun close() = httpClient.close() } + val sleeper = RecordingSleeper() val retryingClient = RetryingHttpClient.builder() .httpClient(failingHttpClient) .maxRetries(2) - .sleeper( - object : Sleeper { - - override fun sleep(duration: Duration) {} - - override fun sleepAsync(duration: Duration): CompletableFuture = - CompletableFuture.completedFuture(null) - - override fun close() {} - } - ) + .sleeper(sleeper) .build() val response = @@ -339,25 +369,153 @@ internal class RetryingHttpClientTest { postRequestedFor(urlPathEqualTo("/something")) .withHeader("x-stainless-retry-count", equalTo("0")), ) + // Exponential backoff with jitter: 0.5s * jitter where jitter is in [0.75, 1.0]. + assertThat(sleeper.durations).hasSize(1) + assertThat(sleeper.durations[0]).isBetween(Duration.ofMillis(375), Duration.ofMillis(500)) assertNoResponseLeaks() } - private fun retryingHttpClientBuilder() = - RetryingHttpClient.builder() - .httpClient(httpClient) - // Use a no-op `Sleeper` to make the test fast. - .sleeper( - object : Sleeper { + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withExponentialBackoff(async: Boolean) { + stubFor(post(urlPathEqualTo("/something")).willReturn(serviceUnavailable())) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).maxRetries(3).build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, + ) - override fun sleep(duration: Duration) {} + // All retries exhausted; the last 503 response is returned. + assertThat(response.statusCode()).isEqualTo(503) + verify(4, postRequestedFor(urlPathEqualTo("/something"))) + // Exponential backoff with jitter: backoff = min(0.5 * 2^(retries-1), 8) * jitter where + // jitter is in [0.75, 1.0]. + assertThat(sleeper.durations).hasSize(3) + // retries=1: 0.5s * [0.75, 1.0] + assertThat(sleeper.durations[0]).isBetween(Duration.ofMillis(375), Duration.ofMillis(500)) + // retries=2: 1.0s * [0.75, 1.0] + assertThat(sleeper.durations[1]).isBetween(Duration.ofMillis(750), Duration.ofMillis(1000)) + // retries=3: 2.0s * [0.75, 1.0] + assertThat(sleeper.durations[2]).isBetween(Duration.ofMillis(1500), Duration.ofMillis(2000)) + assertNoResponseLeaks() + } - override fun sleepAsync(duration: Duration): CompletableFuture = - CompletableFuture.completedFuture(null) + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withExponentialBackoffCap(async: Boolean) { + stubFor(post(urlPathEqualTo("/something")).willReturn(serviceUnavailable())) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).maxRetries(6).build() - override fun close() {} - } + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, ) + assertThat(response.statusCode()).isEqualTo(503) + verify(7, postRequestedFor(urlPathEqualTo("/something"))) + assertThat(sleeper.durations).hasSize(6) + // retries=5: min(0.5 * 2^4, 8) = 8.0s * [0.75, 1.0] + assertThat(sleeper.durations[4]).isBetween(Duration.ofMillis(6000), Duration.ofMillis(8000)) + // retries=6: min(0.5 * 2^5, 8) = min(16, 8) = 8.0s * [0.75, 1.0] (capped) + assertThat(sleeper.durations[5]).isBetween(Duration.ofMillis(6000), Duration.ofMillis(8000)) + assertNoResponseLeaks() + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withRetryAfterMsPriorityOverRetryAfter(async: Boolean) { + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + serviceUnavailable() + .withHeader("Retry-After-Ms", "50") + .withHeader("Retry-After", "2") + ) + .willSetStateTo("RETRY") + ) + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") + .whenScenarioStateIs("RETRY") + .willReturn(ok()) + .willSetStateTo("COMPLETED") + ) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).maxRetries(1).build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, + ) + + assertThat(response.statusCode()).isEqualTo(200) + // Retry-After-Ms (50ms) takes priority over Retry-After (2s). + assertThat(sleeper.durations).containsExactly(Duration.ofMillis(50)) + assertNoResponseLeaks() + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withRetryAfterUnparseable(async: Boolean) { + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn(serviceUnavailable().withHeader("Retry-After", "not-a-date-or-number")) + .willSetStateTo("RETRY") + ) + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") + .whenScenarioStateIs("RETRY") + .willReturn(ok()) + .willSetStateTo("COMPLETED") + ) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).maxRetries(1).build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, + ) + + assertThat(response.statusCode()).isEqualTo(200) + // Unparseable Retry-After falls through to exponential backoff. + assertThat(sleeper.durations).hasSize(1) + assertThat(sleeper.durations[0]).isBetween(Duration.ofMillis(375), Duration.ofMillis(500)) + assertNoResponseLeaks() + } + + private fun retryingHttpClientBuilder( + sleeper: RecordingSleeper, + clock: Clock = Clock.systemUTC(), + ) = RetryingHttpClient.builder().httpClient(httpClient).sleeper(sleeper).clock(clock) + private fun HttpClient.execute(request: HttpRequest, async: Boolean): HttpResponse = if (async) executeAsync(request).get() else execute(request) From a76719edc99a3a43bb71f9d7399d7fcc19fa4327 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 12:34:53 +0000 Subject: [PATCH 33/41] chore(internal): codegen related update --- .github/workflows/ci.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e28263d..2865a6a 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/**' From 8d85b734b31a8fbf779fb80be8e6a12ac0a97e12 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Mar 2026 11:55:08 +0000 Subject: [PATCH 34/41] chore(internal): codegen related update --- .../com/phoebe/api/core/ClientOptions.kt | 7 +++--- .../com/phoebe/api/core/ClientOptionsTest.kt | 23 +++++++++++++++++++ .../api/core/http/RetryingHttpClientTest.kt | 8 +++---- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ClientOptions.kt b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ClientOptions.kt index 9efbc61..a5d109f 100644 --- a/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ClientOptions.kt +++ b/phoebe-java-core/src/main/kotlin/com/phoebe/api/core/ClientOptions.kt @@ -403,13 +403,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("X-eBirdApiToken", it) + headers.replace("X-eBirdApiToken", it) } } - headers.replaceAll(this.headers.build()) - queryParams.replaceAll(this.queryParams.build()) return ClientOptions( httpClient, diff --git a/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ClientOptionsTest.kt b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ClientOptionsTest.kt index 9c6b5c4..dfb922a 100644 --- a/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ClientOptionsTest.kt +++ b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/ClientOptionsTest.kt @@ -16,6 +16,29 @@ internal class ClientOptionsTest { private val httpClient = mock() + @Test + fun putHeader_canOverwriteDefaultHeader() { + val clientOptions = + ClientOptions.builder() + .httpClient(httpClient) + .putHeader("User-Agent", "My User Agent") + .apiKey("My API Key") + .build() + + assertThat(clientOptions.headers.values("User-Agent")).containsExactly("My User Agent") + } + + @Test + fun toBuilder_apiKeyHeaderCanBeUpdated() { + var clientOptions = + ClientOptions.builder().httpClient(httpClient).apiKey("My API Key").build() + + clientOptions = clientOptions.toBuilder().apiKey("another My API Key").build() + + assertThat(clientOptions.headers.values("X-eBirdApiToken")) + .containsExactly("another My API Key") + } + @Test fun toBuilder_whenOriginalClientOptionsGarbageCollected_doesNotCloseOriginalClient() { var clientOptions = diff --git a/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt index cd79e0f..06ad6d8 100644 --- a/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt +++ b/phoebe-java-core/src/test/kotlin/com/phoebe/api/core/http/RetryingHttpClientTest.kt @@ -400,9 +400,9 @@ internal class RetryingHttpClientTest { assertThat(sleeper.durations).hasSize(3) // retries=1: 0.5s * [0.75, 1.0] assertThat(sleeper.durations[0]).isBetween(Duration.ofMillis(375), Duration.ofMillis(500)) - // retries=2: 1.0s * [0.75, 1.0] + // retries=2: 1s * [0.75, 1.0] assertThat(sleeper.durations[1]).isBetween(Duration.ofMillis(750), Duration.ofMillis(1000)) - // retries=3: 2.0s * [0.75, 1.0] + // retries=3: 2s * [0.75, 1.0] assertThat(sleeper.durations[2]).isBetween(Duration.ofMillis(1500), Duration.ofMillis(2000)) assertNoResponseLeaks() } @@ -427,9 +427,9 @@ internal class RetryingHttpClientTest { assertThat(response.statusCode()).isEqualTo(503) verify(7, postRequestedFor(urlPathEqualTo("/something"))) assertThat(sleeper.durations).hasSize(6) - // retries=5: min(0.5 * 2^4, 8) = 8.0s * [0.75, 1.0] + // retries=5: backoff hits the 8s cap * [0.75, 1.0] assertThat(sleeper.durations[4]).isBetween(Duration.ofMillis(6000), Duration.ofMillis(8000)) - // retries=6: min(0.5 * 2^5, 8) = min(16, 8) = 8.0s * [0.75, 1.0] (capped) + // retries=6: still capped at 8s * [0.75, 1.0] assertThat(sleeper.durations[5]).isBetween(Duration.ofMillis(6000), Duration.ofMillis(8000)) assertNoResponseLeaks() } From 98d74bf8a9919494cd924d1a35c43e76effb9128 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 03:57:14 +0000 Subject: [PATCH 35/41] chore(internal): codegen related update --- .../src/main/kotlin/phoebe.kotlin.gradle.kts | 2 +- scripts/fast-format | 6 ++--- scripts/mock | 26 +++++++++---------- scripts/test | 16 ++++++------ 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/buildSrc/src/main/kotlin/phoebe.kotlin.gradle.kts b/buildSrc/src/main/kotlin/phoebe.kotlin.gradle.kts index 9478991..fcff407 100644 --- a/buildSrc/src/main/kotlin/phoebe.kotlin.gradle.kts +++ b/buildSrc/src/main/kotlin/phoebe.kotlin.gradle.kts @@ -40,7 +40,7 @@ tasks.withType().configureEach { val ktfmt by configurations.creating dependencies { - ktfmt("com.facebook:ktfmt:0.56") + ktfmt("com.facebook:ktfmt:0.61") } fun registerKtfmt( diff --git a/scripts/fast-format b/scripts/fast-format index 1b3bc47..35a1dee 100755 --- a/scripts/fast-format +++ b/scripts/fast-format @@ -24,8 +24,8 @@ if [ ! -f "$FILE_LIST" ]; then exit 1 fi -if ! command -v ktfmt-fast-format &> /dev/null; then - echo "Error: ktfmt-fast-format not found" +if ! command -v ktfmt &> /dev/null; then + echo "Error: ktfmt not found" exit 1 fi @@ -36,7 +36,7 @@ echo "==> Done looking for Kotlin files" if [[ -n "$kt_files" ]]; then echo "==> will format Kotlin files" - echo "$kt_files" | tr '\n' '\0' | xargs -0 ktfmt-fast-format --kotlinlang-style "$@" + echo "$kt_files" | tr '\n' '\0' | xargs -0 ktfmt --kotlinlang-style "$@" else echo "No Kotlin files to format -- expected outcome during incremental formatting" fi diff --git a/scripts/mock b/scripts/mock index bcf3b39..38201de 100755 --- a/scripts/mock +++ b/scripts/mock @@ -19,34 +19,34 @@ fi echo "==> Starting mock server with URL ${URL}" -# Run prism mock on the given spec +# Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version + npm exec --package=@stdy/cli@0.19.3 -- steady --version - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & + npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-query-object-format=brackets "$URL" &> .stdy.log & - # Wait for server to come online (max 30s) + # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" attempts=0 - while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + while ! curl --silent --fail "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1; do + if ! kill -0 $! 2>/dev/null; then + echo + cat .stdy.log + exit 1 + fi attempts=$((attempts + 1)) if [ "$attempts" -ge 300 ]; then echo - echo "Timed out waiting for Prism server to start" - cat .prism.log + echo "Timed out waiting for Steady server to start" + cat .stdy.log exit 1 fi 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" + npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 047bc1d..0d08465 100755 --- a/scripts/test +++ b/scripts/test @@ -9,8 +9,8 @@ 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 +function steady_is_running() { + curl --silent "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1 } kill_server_on_port() { @@ -25,7 +25,7 @@ function is_overriding_api_base_url() { [ -n "$TEST_API_BASE_URL" ] } -if ! is_overriding_api_base_url && ! prism_is_running ; then +if ! is_overriding_api_base_url && ! steady_is_running ; then # When we exit this script, make sure to kill the background mock server process trap 'kill_server_on_port 4010' EXIT @@ -36,19 +36,19 @@ 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" +elif ! steady_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Steady 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 -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.3 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-query-object-format=brackets${NC}" echo exit 1 else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo -e "${GREEN}✔ Mock steady server is running with your OpenAPI spec${NC}" echo fi From d13e25d23ef3cf150699d27a46026d78c64ecc9d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 21 Mar 2026 04:56:41 +0000 Subject: [PATCH 36/41] chore(internal): codegen related update --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 38201de..ab814d3 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.3 -- steady --version + npm exec --package=@stdy/cli@0.19.5 -- steady --version - npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 0d08465..7ca8bb4 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.3 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.5 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 From 8beb9ab95768a177d22b20aa3d4c1291b516cd31 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2026 05:03:21 +0000 Subject: [PATCH 37/41] chore(internal): codegen related update --- .gitignore | 1 + scripts/mock | 6 +++--- scripts/test | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) 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/scripts/mock b/scripts/mock index ab814d3..b319bdf 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.5 -- steady --version + npm exec --package=@stdy/cli@0.19.6 -- steady --version - npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 7ca8bb4..cc7059c 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.5 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.6 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 From 4349d5372ce68b707353a71d8db12dffcbb0475f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 03:23:50 +0000 Subject: [PATCH 38/41] chore(internal): codegen related update --- .github/workflows/ci.yml | 4 ++-- scripts/mock | 6 +++--- scripts/test | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2865a6a..2981058 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: timeout-minutes: 15 name: lint runs-on: ${{ github.repository == 'stainless-sdks/phoebe-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 @@ -46,7 +46,7 @@ jobs: contents: read id-token: write runs-on: ${{ github.repository == 'stainless-sdks/phoebe-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 diff --git a/scripts/mock b/scripts/mock index b319bdf..09eb49f 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.6 -- steady --version + npm exec --package=@stdy/cli@0.19.7 -- steady --version - npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index cc7059c..ec1f890 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.6 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 From f24ff7de7b1830d92d031d6482e506b1a5806101 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Mar 2026 06:27:12 +0000 Subject: [PATCH 39/41] chore(internal): codegen related update --- scripts/mock | 4 ++-- scripts/test | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/mock b/scripts/mock index 09eb49f..290e21b 100755 --- a/scripts/mock +++ b/scripts/mock @@ -24,7 +24,7 @@ if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout npm exec --package=@stdy/cli@0.19.7 -- steady --version - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index ec1f890..415d174 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 From 354d5177e6816e06d62e4ab27e032efa7bfa528d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 08:34:29 +0000 Subject: [PATCH 40/41] chore(internal): codegen related update --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 290e21b..5cd7c15 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.7 -- steady --version + npm exec --package=@stdy/cli@0.20.2 -- steady --version - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 415d174..61c1163 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.20.2 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 From bccb7ad132c5c7652cd526387a82dbbdf89a3efe Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 08:35:08 +0000 Subject: [PATCH 41/41] release: 0.1.0-alpha.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 99 +++++++++++++++++++++++++++++++++++ README.md | 10 ++-- build.gradle.kts | 2 +- 4 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c476280..ba6c348 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.0.1-alpha.0" + ".": "0.1.0-alpha.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d847ddd --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,99 @@ +# Changelog + +## 0.1.0-alpha.1 (2026-04-01) + +Full Changelog: [v0.0.1-alpha.0...v0.1.0-alpha.1](https://github.com/phoebe-bird/phoebe-java/compare/v0.0.1-alpha.0...v0.1.0-alpha.1) + +### ⚠ BREAKING CHANGES + +* **client:** change precision of some numeric types +* **client:** extract auto pagination to shared classes +* **client:** **Migration:** - If you were referencing the `AutoPager` class on a specific `*Page` or `*PageAsync` type, then you should instead reference the shared `AutoPager` and `AutoPagerAsync` types, under the `core` package + - `AutoPagerAsync` now has different usage. You can call `.subscribe(...)` on the returned object instead to get called back each page item. You can also call `onCompleteFuture()` to get a future that completes when all items have been processed. Finally, you can call `.close()` on the returned object to stop auto-paginating early + - If you were referencing `getNextPage` or `getNextPageParams`: + - Swap to `nextPage()` and `nextPageParams()` + - Note that these both now return non-optional types (use `hasNextPage()` before calling these, since they will throw if it's impossible to get another page) + +### Features + +* **api:** manual updates ([d712abb](https://github.com/phoebe-bird/phoebe-java/commit/d712abbfc3f4e8e54e8391ae34616bae45510b27)) +* **client:** add `{QueryParams,Headers}#put(String, JsonValue)` methods ([31f7acd](https://github.com/phoebe-bird/phoebe-java/commit/31f7acd90ff3c222f4db984e29ef8a090ce557d6)) +* **client:** add `HttpRequest#url()` method ([a145b94](https://github.com/phoebe-bird/phoebe-java/commit/a145b94467e13633c59889cccd0c26b0b3789a44)) +* **client:** add a `withOptions` method ([008f2ee](https://github.com/phoebe-bird/phoebe-java/commit/008f2ee04e6216121f6bfdf31616a69f0143d55e)) +* **client:** add https config options ([74d088e](https://github.com/phoebe-bird/phoebe-java/commit/74d088e2486ecc1d43474dc0e928905c7eecdfe8)) +* **client:** allow configuring dispatcher executor service ([ef7c266](https://github.com/phoebe-bird/phoebe-java/commit/ef7c2660841ba59c269caa78b58f9a9f59fa162c)) +* **client:** allow configuring env via system properties ([f1de279](https://github.com/phoebe-bird/phoebe-java/commit/f1de279091ccdbf3ace91ed860f1d00345fb6c71)) +* **client:** allow providing some params positionally ([b24d6c0](https://github.com/phoebe-bird/phoebe-java/commit/b24d6c0cd3ecc5a55a382454f96bbf89a84fd3d7)) +* **client:** extract auto pagination to shared classes ([13f571f](https://github.com/phoebe-bird/phoebe-java/commit/13f571f7baf0caef24ce9c554b244476ed3e812b)) +* **client:** implement per-endpoint base URL support ([f493836](https://github.com/phoebe-bird/phoebe-java/commit/f4938363ced1c863b72b10c787c73c56ab6aac51)) +* **client:** send `X-Stainless-Kotlin-Version` header ([d9f18bd](https://github.com/phoebe-bird/phoebe-java/commit/d9f18bd66b86423c4ae710ea0987fe35f53ed457)) + + +### Bug Fixes + +* **client:** bump max requests per host to max requests (5 -> 64) ([73b4311](https://github.com/phoebe-bird/phoebe-java/commit/73b4311a77e11406a4c591ef9bf111ef84970605)) +* **client:** cancel okhttp call when future cancelled ([5823aba](https://github.com/phoebe-bird/phoebe-java/commit/5823abafce2a92fbb69a0f6c23db79a78b78f2a8)) +* **client:** disallow coercion from float to int ([d00944f](https://github.com/phoebe-bird/phoebe-java/commit/d00944fd323009658808104c8a4b3954211b3559)) +* **client:** don't close client on `withOptions` usage when original is gc'd ([3d3f673](https://github.com/phoebe-bird/phoebe-java/commit/3d3f673ecda4ce417d1ec954ea670cf629ae373a)) +* **client:** ensure error handling always occurs ([c4327a3](https://github.com/phoebe-bird/phoebe-java/commit/c4327a3c088df1b9398337114f3316f5e355a7f3)) +* **client:** fully respect max retries ([7c71f9d](https://github.com/phoebe-bird/phoebe-java/commit/7c71f9dc52f85d1a055e25f5d940ac1fc6d807b0)) +* **client:** preserve time zone in lenient date-time parsing ([50bb540](https://github.com/phoebe-bird/phoebe-java/commit/50bb540673b947b6f5b2da24bb3cac46e3ca498a)) +* **client:** remove `@MustBeClosed` for future returning methods ([a6e5c78](https://github.com/phoebe-bird/phoebe-java/commit/a6e5c78fcb9b3107791323d3c3da12791634939a)) +* **client:** send retry count header for max retries 0 ([7c71f9d](https://github.com/phoebe-bird/phoebe-java/commit/7c71f9dc52f85d1a055e25f5d940ac1fc6d807b0)) +* date time deserialization leniency ([9d5f042](https://github.com/phoebe-bird/phoebe-java/commit/9d5f042b85f9bdaec3a56ad6ea180a32f6a5f454)) + + +### Chores + +* **ci:** enable for pull requests ([30e9e4a](https://github.com/phoebe-bird/phoebe-java/commit/30e9e4af5c35b09de9c58934e263d3a6b667d3fa)) +* **ci:** only run for pushes and fork pull requests ([a3e1190](https://github.com/phoebe-bird/phoebe-java/commit/a3e119093c0f9c11ee28bef632aca42deb6635b2)) +* **ci:** skip uploading artifacts on stainless-internal branches ([5945140](https://github.com/phoebe-bird/phoebe-java/commit/5945140f250d2b0ae6c2d9cd3fc3ee386a65ffc8)) +* **ci:** upgrade `actions/github-script` ([43107c0](https://github.com/phoebe-bird/phoebe-java/commit/43107c0efbf857c052a1ce799f14a45add565375)) +* **ci:** upgrade `actions/setup-java` ([75d7ae3](https://github.com/phoebe-bird/phoebe-java/commit/75d7ae3dc40b246a7fe1e4a0316122c579779edd)) +* configure new SDK language ([30ab2b2](https://github.com/phoebe-bird/phoebe-java/commit/30ab2b26361936249dbea4db64787cfc7c6b7e2d)) +* **docs:** grammar improvements ([33fa7c5](https://github.com/phoebe-bird/phoebe-java/commit/33fa7c53610ea31ad671e5c5437fa6d4d02290a9)) +* **internal:** allow running specific example from cli ([56695c9](https://github.com/phoebe-bird/phoebe-java/commit/56695c9e55d80e78608e41f4f90297f13d100c22)) +* **internal:** clean up maven repo artifact script and add html documentation to repo root ([6a0f2ca](https://github.com/phoebe-bird/phoebe-java/commit/6a0f2cab131804296e2b29cc2e29c58de3603a2b)) +* **internal:** codegen related update ([354d517](https://github.com/phoebe-bird/phoebe-java/commit/354d5177e6816e06d62e4ab27e032efa7bfa528d)) +* **internal:** codegen related update ([f24ff7d](https://github.com/phoebe-bird/phoebe-java/commit/f24ff7de7b1830d92d031d6482e506b1a5806101)) +* **internal:** codegen related update ([4349d53](https://github.com/phoebe-bird/phoebe-java/commit/4349d5372ce68b707353a71d8db12dffcbb0475f)) +* **internal:** codegen related update ([8beb9ab](https://github.com/phoebe-bird/phoebe-java/commit/8beb9ab95768a177d22b20aa3d4c1291b516cd31)) +* **internal:** codegen related update ([d13e25d](https://github.com/phoebe-bird/phoebe-java/commit/d13e25d23ef3cf150699d27a46026d78c64ecc9d)) +* **internal:** codegen related update ([98d74bf](https://github.com/phoebe-bird/phoebe-java/commit/98d74bf8a9919494cd924d1a35c43e76effb9128)) +* **internal:** codegen related update ([8d85b73](https://github.com/phoebe-bird/phoebe-java/commit/8d85b734b31a8fbf779fb80be8e6a12ac0a97e12)) +* **internal:** codegen related update ([a76719e](https://github.com/phoebe-bird/phoebe-java/commit/a76719edc99a3a43bb71f9d7399d7fcc19fa4327)) +* **internal:** codegen related update ([102eb54](https://github.com/phoebe-bird/phoebe-java/commit/102eb54ea114aa3741df602701d022c2bf7f038f)) +* **internal:** codegen related update ([ea5500a](https://github.com/phoebe-bird/phoebe-java/commit/ea5500a64b0688e57f2ca9f3dee0eaaa74d9f860)) +* **internal:** codegen related update ([9b9b899](https://github.com/phoebe-bird/phoebe-java/commit/9b9b899e5b9186438c76ddc90a0b2fe65a21ef17)) +* **internal:** codegen related update ([b07058d](https://github.com/phoebe-bird/phoebe-java/commit/b07058d9f6e68617a2c01194deabd50547848f87)) +* **internal:** codegen related update ([26cd70c](https://github.com/phoebe-bird/phoebe-java/commit/26cd70c6547384e153a6abf88178fbed6e8c2951)) +* **internal:** codegen related update ([2082664](https://github.com/phoebe-bird/phoebe-java/commit/20826641ea001336618b19ceaf63acd87ed82d9f)) +* **internal:** codegen related update ([17f6183](https://github.com/phoebe-bird/phoebe-java/commit/17f6183f74d414255db7fe82cbc6e73b09430d06)) +* **internal:** codegen related update ([fa74474](https://github.com/phoebe-bird/phoebe-java/commit/fa744740ab0421e1a3ed33aad5952fde2e80c4df)) +* **internal:** codegen related update ([78f6424](https://github.com/phoebe-bird/phoebe-java/commit/78f64241e6e1a7f11b3004ea3b40e282688e473d)) +* **internal:** codegen related update ([704a4e1](https://github.com/phoebe-bird/phoebe-java/commit/704a4e190b022602ad545cf926ef21ce4bac5d96)) +* **internal:** codegen related update ([e57fa55](https://github.com/phoebe-bird/phoebe-java/commit/e57fa556588b355f889962a6e57cf041a2ab7b5c)) +* **internal:** codegen related update ([44125db](https://github.com/phoebe-bird/phoebe-java/commit/44125db5522d48fb720c0753aeada71cab6e3105)) +* **internal:** correct cache invalidation for `SKIP_MOCK_TESTS` ([adfd7da](https://github.com/phoebe-bird/phoebe-java/commit/adfd7da05a09ef5622316700c031b6ac6ef4d05f)) +* **internal:** depend on packages directly in example ([7c71f9d](https://github.com/phoebe-bird/phoebe-java/commit/7c71f9dc52f85d1a055e25f5d940ac1fc6d807b0)) +* **internal:** improve maven repo docs ([da49cb7](https://github.com/phoebe-bird/phoebe-java/commit/da49cb77739c9becf5d45b12095298950f1e32f9)) +* **internal:** refactor delegating from client to options ([4ea1ff5](https://github.com/phoebe-bird/phoebe-java/commit/4ea1ff5ee41e8e81d62000b0bac199c47d645b8e)) +* **internal:** remove unnecessary `[...]` in `[@see](https://github.com/see)` ([bed463e](https://github.com/phoebe-bird/phoebe-java/commit/bed463e241505d386c28f49a7c0edbfaa9c4e3be)) +* **internal:** support uploading Maven repo artifacts to stainless package server ([37c89f8](https://github.com/phoebe-bird/phoebe-java/commit/37c89f8c816525461bce82b5550d796ff1ff3023)) +* **internal:** update `actions/checkout` version ([3a146bb](https://github.com/phoebe-bird/phoebe-java/commit/3a146bbdb3ab84f558391f3b8e6bc7e2c8fd77f6)) +* **internal:** update maven repo doc to include authentication ([cf7eb23](https://github.com/phoebe-bird/phoebe-java/commit/cf7eb239f388de322581a476a6e6845cebd5e019)) +* test on Jackson 2.14.0 to avoid encountering FasterXML/jackson-databind[#3240](https://github.com/phoebe-bird/phoebe-java/issues/3240) in tests ([9d5f042](https://github.com/phoebe-bird/phoebe-java/commit/9d5f042b85f9bdaec3a56ad6ea180a32f6a5f454)) + + +### Documentation + +* fix missing readme comment ([4fd91a7](https://github.com/phoebe-bird/phoebe-java/commit/4fd91a77d9e1291a5d81ee0cc950d4a83e2ab753)) +* more code comments ([f8420f4](https://github.com/phoebe-bird/phoebe-java/commit/f8420f4dfd2e03fae3e61c5b7884f425c92b69d8)) +* prominently feature MCP server setup in root SDK readmes ([7754ce1](https://github.com/phoebe-bird/phoebe-java/commit/7754ce1495022f309ff26d5c2f06f3c4c8e913b7)) +* remove `$` for better copy-pasteabality ([fe8a020](https://github.com/phoebe-bird/phoebe-java/commit/fe8a02007be585c2c162442e968a4fe8909eb39e)) + + +### Refactors + +* **client:** change precision of some numeric types ([c593d52](https://github.com/phoebe-bird/phoebe-java/commit/c593d52bf58fc1324aef2f61d1411a0923b15a2e)) +* **internal:** minor `ClientOptionsTest` change ([b9a8ca8](https://github.com/phoebe-bird/phoebe-java/commit/b9a8ca82aa21e634734848084170f7930b906684)) diff --git a/README.md b/README.md index 27bc751..ef9ad85 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.phoebe.api/phoebe-java)](https://central.sonatype.com/artifact/com.phoebe.api/phoebe-java/0.0.1-alpha.0) -[![javadoc](https://javadoc.io/badge2/com.phoebe.api/phoebe-java/0.0.1-alpha.0/javadoc.svg)](https://javadoc.io/doc/com.phoebe.api/phoebe-java/0.0.1-alpha.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.phoebe.api/phoebe-java)](https://central.sonatype.com/artifact/com.phoebe.api/phoebe-java/0.1.0-alpha.1) +[![javadoc](https://javadoc.io/badge2/com.phoebe.api/phoebe-java/0.1.0-alpha.1/javadoc.svg)](https://javadoc.io/doc/com.phoebe.api/phoebe-java/0.1.0-alpha.1) @@ -22,7 +22,7 @@ Use the Phoebe MCP Server to enable AI assistants to interact with this API, all -The REST API documentation can be found on [science.ebird.org](https://science.ebird.org/en/use-ebird-data/download-ebird-data-products). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.phoebe.api/phoebe-java/0.0.1-alpha.0). +The REST API documentation can be found on [science.ebird.org](https://science.ebird.org/en/use-ebird-data/download-ebird-data-products). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.phoebe.api/phoebe-java/0.1.0-alpha.1). @@ -33,7 +33,7 @@ The REST API documentation can be found on [science.ebird.org](https://science.e ### Gradle ```kotlin -implementation("com.phoebe.api:phoebe-java:0.0.1-alpha.0") +implementation("com.phoebe.api:phoebe-java:0.1.0-alpha.1") ``` ### Maven @@ -42,7 +42,7 @@ implementation("com.phoebe.api:phoebe-java:0.0.1-alpha.0") com.phoebe.api phoebe-java - 0.0.1-alpha.0 + 0.1.0-alpha.1 ``` diff --git a/build.gradle.kts b/build.gradle.kts index bccbd2e..dd5d657 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.phoebe.api" - version = "0.0.1-alpha.0" // x-release-please-version + version = "0.1.0-alpha.1" // x-release-please-version } subprojects {