Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,18 @@ jobs:
run: ./scripts/build

- name: Get GitHub OIDC Token
if: github.repository == 'stainless-sdks/stagehand-java'
if: |-
github.repository == 'stainless-sdks/stagehand-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/stagehand-java'
if: |-
github.repository == 'stainless-sdks/stagehand-java' &&
!startsWith(github.ref, 'refs/heads/stl/')
env:
URL: https://pkg.stainless.com/s
AUTH: ${{ steps.github-oidc.outputs.github_token }}
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.7.1"
".": "0.8.0"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 8
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-a4e672f457dd99336f4b2a113fd7c7c6c9db0941b38d57cff6e3641549a6c4ed.yml
openapi_spec_hash: eae9c8561e420db8e4d238c1e59617fb
config_hash: 2a565ad6662259a2e90fa5f1f5095525
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-573d364768ac1902ee5ed8b2485d3b293bda0ea8ff7898aef1a3fd6be79b594a.yml
openapi_spec_hash: 107ec840f4330885dd2232a05a66fed7
config_hash: 0209737a4ab2a71afececb0ff7459998
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Changelog

## 0.8.0 (2026-03-11)

Full Changelog: [v0.7.1...v0.8.0](https://github.com/browserbase/stagehand-java/compare/v0.7.1...v0.8.0)

### Features

* Add missing cdpHeaders field to v3 server openapi spec ([5a9506d](https://github.com/browserbase/stagehand-java/commit/5a9506d5dfeb1ae172834941aad3bbd9e96f2973))


### Bug Fixes

* **client:** incorrect `Retry-After` parsing ([76ea3fc](https://github.com/browserbase/stagehand-java/commit/76ea3fc583bfe9ca7295856db85378b44d765b0f))


### Chores

* **ci:** skip uploading artifacts on stainless-internal branches ([4a1399c](https://github.com/browserbase/stagehand-java/commit/4a1399c7a535d9bf8934e9d142878e57a1537b8d))
* **internal:** bump palantir-java-format ([3bf036a](https://github.com/browserbase/stagehand-java/commit/3bf036aed5ba8fb90fe4bf5bc6b62a49f09f7dcc))
* **internal:** codegen related update ([f94c8c9](https://github.com/browserbase/stagehand-java/commit/f94c8c9a86af4592fba5c42645ccc1099a8ab1fe))

## 0.7.1 (2026-03-04)

Full Changelog: [v0.7.0...v0.7.1](https://github.com/browserbase/stagehand-java/compare/v0.7.0...v0.7.1)
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

<!-- x-release-please-start-version -->

[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.7.1)
[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.7.1/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.7.1)
[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.8.0)
[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.8.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.8.0)

<!-- x-release-please-end -->

Expand Down Expand Up @@ -85,7 +85,7 @@ Most existing browser automation tools either require you to write low-level cod
### Gradle

```kotlin
implementation("com.browserbase.api:stagehand-java:0.7.1")
implementation("com.browserbase.api:stagehand-java:0.8.0")
```

### Maven
Expand All @@ -94,7 +94,7 @@ implementation("com.browserbase.api:stagehand-java:0.7.1")
<dependency>
<groupId>com.browserbase.api</groupId>
<artifactId>stagehand-java</artifactId>
<version>0.7.1</version>
<version>0.8.0</version>
</dependency>
```

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ repositories {

allprojects {
group = "com.browserbase.api"
version = "0.7.1" // x-release-please-version
version = "0.8.0" // x-release-please-version
}

subprojects {
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/stagehand.java.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ tasks.withType<Test>().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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,7 @@ private constructor(
private constructor(
private val acceptDownloads: JsonField<Boolean>,
private val args: JsonField<List<String>>,
private val cdpHeaders: JsonField<CdpHeaders>,
private val cdpUrl: JsonField<String>,
private val chromiumSandbox: JsonField<Boolean>,
private val connectTimeoutMs: JsonField<Double>,
Expand Down Expand Up @@ -1400,6 +1401,9 @@ private constructor(
@JsonProperty("args")
@ExcludeMissing
args: JsonField<List<String>> = JsonMissing.of(),
@JsonProperty("cdpHeaders")
@ExcludeMissing
cdpHeaders: JsonField<CdpHeaders> = JsonMissing.of(),
@JsonProperty("cdpUrl")
@ExcludeMissing
cdpUrl: JsonField<String> = JsonMissing.of(),
Expand Down Expand Up @@ -1450,6 +1454,7 @@ private constructor(
) : this(
acceptDownloads,
args,
cdpHeaders,
cdpUrl,
chromiumSandbox,
connectTimeoutMs,
Expand Down Expand Up @@ -1483,6 +1488,12 @@ private constructor(
*/
fun args(): Optional<List<String>> = args.getOptional("args")

/**
* @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g.
* if the server responded with an unexpected value).
*/
fun cdpHeaders(): Optional<CdpHeaders> = cdpHeaders.getOptional("cdpHeaders")

/**
* @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g.
* if the server responded with an unexpected value).
Expand Down Expand Up @@ -1608,6 +1619,16 @@ private constructor(
*/
@JsonProperty("args") @ExcludeMissing fun _args(): JsonField<List<String>> = args

/**
* Returns the raw JSON value of [cdpHeaders].
*
* Unlike [cdpHeaders], this method doesn't throw if the JSON field has an unexpected
* type.
*/
@JsonProperty("cdpHeaders")
@ExcludeMissing
fun _cdpHeaders(): JsonField<CdpHeaders> = cdpHeaders

/**
* Returns the raw JSON value of [cdpUrl].
*
Expand Down Expand Up @@ -1783,6 +1804,7 @@ private constructor(

private var acceptDownloads: JsonField<Boolean> = JsonMissing.of()
private var args: JsonField<MutableList<String>>? = null
private var cdpHeaders: JsonField<CdpHeaders> = JsonMissing.of()
private var cdpUrl: JsonField<String> = JsonMissing.of()
private var chromiumSandbox: JsonField<Boolean> = JsonMissing.of()
private var connectTimeoutMs: JsonField<Double> = JsonMissing.of()
Expand All @@ -1806,6 +1828,7 @@ private constructor(
internal fun from(launchOptions: LaunchOptions) = apply {
acceptDownloads = launchOptions.acceptDownloads
args = launchOptions.args.map { it.toMutableList() }
cdpHeaders = launchOptions.cdpHeaders
cdpUrl = launchOptions.cdpUrl
chromiumSandbox = launchOptions.chromiumSandbox
connectTimeoutMs = launchOptions.connectTimeoutMs
Expand Down Expand Up @@ -1865,6 +1888,19 @@ private constructor(
}
}

fun cdpHeaders(cdpHeaders: CdpHeaders) = cdpHeaders(JsonField.of(cdpHeaders))

/**
* Sets [Builder.cdpHeaders] to an arbitrary JSON value.
*
* You should usually call [Builder.cdpHeaders] with a well-typed [CdpHeaders] value
* instead. This method is primarily for setting the field to an undocumented or not
* yet supported value.
*/
fun cdpHeaders(cdpHeaders: JsonField<CdpHeaders>) = apply {
this.cdpHeaders = cdpHeaders
}

fun cdpUrl(cdpUrl: String) = cdpUrl(JsonField.of(cdpUrl))

/**
Expand Down Expand Up @@ -2120,6 +2156,7 @@ private constructor(
LaunchOptions(
acceptDownloads,
(args ?: JsonMissing.of()).map { it.toImmutable() },
cdpHeaders,
cdpUrl,
chromiumSandbox,
connectTimeoutMs,
Expand Down Expand Up @@ -2150,6 +2187,7 @@ private constructor(

acceptDownloads()
args()
cdpHeaders().ifPresent { it.validate() }
cdpUrl()
chromiumSandbox()
connectTimeoutMs()
Expand Down Expand Up @@ -2188,6 +2226,7 @@ private constructor(
internal fun validity(): Int =
(if (acceptDownloads.asKnown().isPresent) 1 else 0) +
(args.asKnown().getOrNull()?.size ?: 0) +
(cdpHeaders.asKnown().getOrNull()?.validity() ?: 0) +
(if (cdpUrl.asKnown().isPresent) 1 else 0) +
(if (chromiumSandbox.asKnown().isPresent) 1 else 0) +
(if (connectTimeoutMs.asKnown().isPresent) 1 else 0) +
Expand All @@ -2206,6 +2245,110 @@ private constructor(
(if (userDataDir.asKnown().isPresent) 1 else 0) +
(viewport.asKnown().getOrNull()?.validity() ?: 0)

class CdpHeaders
@JsonCreator
private constructor(
@com.fasterxml.jackson.annotation.JsonValue
private val additionalProperties: Map<String, JsonValue>
) {

@JsonAnyGetter
@ExcludeMissing
fun _additionalProperties(): Map<String, JsonValue> = additionalProperties

fun toBuilder() = Builder().from(this)

companion object {

/** Returns a mutable builder for constructing an instance of [CdpHeaders]. */
@JvmStatic fun builder() = Builder()
}

/** A builder for [CdpHeaders]. */
class Builder internal constructor() {

private var additionalProperties: MutableMap<String, JsonValue> = mutableMapOf()

@JvmSynthetic
internal fun from(cdpHeaders: CdpHeaders) = apply {
additionalProperties = cdpHeaders.additionalProperties.toMutableMap()
}

fun additionalProperties(additionalProperties: Map<String, JsonValue>) = apply {
this.additionalProperties.clear()
putAllAdditionalProperties(additionalProperties)
}

fun putAdditionalProperty(key: String, value: JsonValue) = apply {
additionalProperties.put(key, value)
}

fun putAllAdditionalProperties(additionalProperties: Map<String, JsonValue>) =
apply {
this.additionalProperties.putAll(additionalProperties)
}

fun removeAdditionalProperty(key: String) = apply {
additionalProperties.remove(key)
}

fun removeAllAdditionalProperties(keys: Set<String>) = apply {
keys.forEach(::removeAdditionalProperty)
}

/**
* Returns an immutable instance of [CdpHeaders].
*
* Further updates to this [Builder] will not mutate the returned instance.
*/
fun build(): CdpHeaders = CdpHeaders(additionalProperties.toImmutable())
}

private var validated: Boolean = false

fun validate(): CdpHeaders = apply {
if (validated) {
return@apply
}

validated = true
}

fun isValid(): Boolean =
try {
validate()
true
} catch (e: StagehandInvalidDataException) {
false
}

/**
* Returns a score indicating how many valid values are contained in this object
* recursively.
*
* Used for best match union deserialization.
*/
@JvmSynthetic
internal fun validity(): Int =
additionalProperties.count { (_, value) ->
!value.isNull() && !value.isMissing()
}

override fun equals(other: Any?): Boolean {
if (this === other) {
return true
}

return other is CdpHeaders && additionalProperties == other.additionalProperties
}

private val hashCode: Int by lazy { Objects.hash(additionalProperties) }

override fun hashCode(): Int = hashCode

override fun toString() = "CdpHeaders{additionalProperties=$additionalProperties}"
}

@JsonDeserialize(using = IgnoreDefaultArgs.Deserializer::class)
@JsonSerialize(using = IgnoreDefaultArgs.Serializer::class)
class IgnoreDefaultArgs
Expand Down Expand Up @@ -2872,6 +3015,7 @@ private constructor(
return other is LaunchOptions &&
acceptDownloads == other.acceptDownloads &&
args == other.args &&
cdpHeaders == other.cdpHeaders &&
cdpUrl == other.cdpUrl &&
chromiumSandbox == other.chromiumSandbox &&
connectTimeoutMs == other.connectTimeoutMs &&
Expand All @@ -2896,6 +3040,7 @@ private constructor(
Objects.hash(
acceptDownloads,
args,
cdpHeaders,
cdpUrl,
chromiumSandbox,
connectTimeoutMs,
Expand All @@ -2920,7 +3065,7 @@ private constructor(
override fun hashCode(): Int = hashCode

override fun toString() =
"LaunchOptions{acceptDownloads=$acceptDownloads, args=$args, cdpUrl=$cdpUrl, chromiumSandbox=$chromiumSandbox, connectTimeoutMs=$connectTimeoutMs, deviceScaleFactor=$deviceScaleFactor, devtools=$devtools, downloadsPath=$downloadsPath, executablePath=$executablePath, hasTouch=$hasTouch, headless=$headless, ignoreDefaultArgs=$ignoreDefaultArgs, ignoreHttpsErrors=$ignoreHttpsErrors, locale=$locale, port=$port, preserveUserDataDir=$preserveUserDataDir, proxy=$proxy, userDataDir=$userDataDir, viewport=$viewport, additionalProperties=$additionalProperties}"
"LaunchOptions{acceptDownloads=$acceptDownloads, args=$args, cdpHeaders=$cdpHeaders, cdpUrl=$cdpUrl, chromiumSandbox=$chromiumSandbox, connectTimeoutMs=$connectTimeoutMs, deviceScaleFactor=$deviceScaleFactor, devtools=$devtools, downloadsPath=$downloadsPath, executablePath=$executablePath, hasTouch=$hasTouch, headless=$headless, ignoreDefaultArgs=$ignoreDefaultArgs, ignoreHttpsErrors=$ignoreHttpsErrors, locale=$locale, port=$port, preserveUserDataDir=$preserveUserDataDir, proxy=$proxy, userDataDir=$userDataDir, viewport=$viewport, additionalProperties=$additionalProperties}"
}

/** Browser type to use */
Expand Down
Loading