From 07c0ca079a3ed09d2350d320323b616e471d0b03 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Wed, 19 Aug 2026 18:31:54 -0700 Subject: [PATCH 1/3] feat(devboxes): use optimistic create endpoint (#825) --- src/resources/devboxes/devboxes.ts | 8 ++++++- tests/api-resources/devboxes/devboxes.test.ts | 22 ++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/resources/devboxes/devboxes.ts b/src/resources/devboxes/devboxes.ts index d88aac1ab..947c864d0 100644 --- a/src/resources/devboxes/devboxes.ts +++ b/src/resources/devboxes/devboxes.ts @@ -131,7 +131,13 @@ export class Devboxes extends APIResource { options?: LongPollRequestOptions, ): Promise { const { longPoll, polling, ...requestOptions } = options ?? {}; - const devbox = await this.create(body, requestOptions); + const devbox = (await this._client.post('/v1/devboxes/create_and_await_running', { + body: body ?? {}, + ...requestOptions, + })) as DevboxView; + if (devbox.status === 'running') { + return devbox; + } return this.awaitRunning(devbox.id, { ...requestOptions, longPoll, polling }); } /** diff --git a/tests/api-resources/devboxes/devboxes.test.ts b/tests/api-resources/devboxes/devboxes.test.ts index 9f547d3bf..1ad1d9ee3 100644 --- a/tests/api-resources/devboxes/devboxes.test.ts +++ b/tests/api-resources/devboxes/devboxes.test.ts @@ -716,7 +716,7 @@ describe('resource devboxes', () => { expect(mockPost).toHaveBeenCalledTimes(2); // Check create call - expect(mockPost).toHaveBeenNthCalledWith(1, '/v1/devboxes', { + expect(mockPost).toHaveBeenNthCalledWith(1, '/v1/devboxes/create_and_await_running', { body: { name: 'test-devbox' }, }); @@ -731,16 +731,28 @@ describe('resource devboxes', () => { mockPost.mockRestore(); }); + test('createAndAwaitRunning: returns an optimistic running response without polling', async () => { + const mockPost = jest.spyOn(client.devboxes['_client'], 'post'); + mockPost.mockResolvedValueOnce({ id: 'new-devbox-id', status: 'running' }); + + const result = await client.devboxes.createAndAwaitRunning({ name: 'test-devbox' }); + + expect(result).toEqual({ id: 'new-devbox-id', status: 'running' }); + expect(mockPost).toHaveBeenCalledTimes(1); + expect(mockPost).toHaveBeenCalledWith('/v1/devboxes/create_and_await_running', { + body: { name: 'test-devbox' }, + }); + }); + test('createAndAwaitRunning: handles creation failure', async () => { const mockPost = jest.spyOn(client.devboxes['_client'], 'post'); - const createError = new Error('Creation failed'); - mockPost.mockRejectedValueOnce(createError); + const createError = new APIError(400, undefined, 'Creation failed', {}); + mockPost.mockRejectedValue(createError); await expect(client.devboxes.createAndAwaitRunning()).rejects.toThrow('Creation failed'); - expect(mockPost).toHaveBeenCalledTimes(1); - expect(mockPost).toHaveBeenCalledWith('/v1/devboxes', { body: {} }); + expect(mockPost).toHaveBeenCalledWith('/v1/devboxes/create_and_await_running', { body: {} }); mockPost.mockRestore(); }); From 627021b4d35e9996fe00a7a263a8e8ab5a83cba5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 23 Aug 2026 23:01:35 +0000 Subject: [PATCH 2/3] chore(internal): allow the mock server port to be set with STAINLESS_MOCK_PORT --- scripts/mock | 13 ++++++++++--- scripts/test | 26 ++++++++++++++++---------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/scripts/mock b/scripts/mock index feebe5ed7..984e1c007 100755 --- a/scripts/mock +++ b/scripts/mock @@ -4,6 +4,11 @@ set -e cd "$(dirname "$0")/.." +if [ "$1" == "--install" ]; then + npm exec --package=@stdy/cli@0.22.1 -- steady --version + exit 0 +fi + if [[ -n "$1" && "$1" != '--'* ]]; then URL="$1" shift @@ -20,16 +25,18 @@ fi echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec +MOCK_PORT="${STAINLESS_MOCK_PORT:-4010}" + if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout npm exec --package=@stdy/cli@0.22.1 -- steady --version - npm exec --package=@stdy/cli@0.22.1 -- 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.22.1 -- steady --host 127.0.0.1 -p "$MOCK_PORT" --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" attempts=0 - while ! curl --silent --fail "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1; do + while ! curl --silent --fail "http://127.0.0.1:$MOCK_PORT/_x-steady/health" >/dev/null 2>&1; do if ! kill -0 $! 2>/dev/null; then echo cat .stdy.log @@ -48,5 +55,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.22.1 -- 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.22.1 -- steady --host 127.0.0.1 -p "$MOCK_PORT" --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 765377693..b5f17650c 100755 --- a/scripts/test +++ b/scripts/test @@ -9,8 +9,10 @@ GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color +MOCK_PORT="${STAINLESS_MOCK_PORT:-4010}" + function steady_is_running() { - curl --silent "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1 + curl --silent "http://127.0.0.1:$MOCK_PORT/_x-steady/health" >/dev/null 2>&1 } # Parse command line arguments @@ -44,7 +46,7 @@ function is_overriding_api_base_url() { 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 + trap 'kill_server_on_port "$MOCK_PORT"' EXIT # Start the dev server ./scripts/mock --daemon @@ -60,7 +62,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.22.1 -- 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.22.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p $MOCK_PORT --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 @@ -69,10 +71,14 @@ else echo fi -if [ "$RUN_SMOKE_TESTS" = true ]; then - echo -e "${YELLOW}==> Running smoke tests${NC}" - RUN_SMOKETESTS=1 ./node_modules/.bin/jest "${JEST_ARGS[@]}" -else - echo "==> Running tests" - ./node_modules/.bin/jest "${JEST_ARGS[@]}" -fi +if [ -n "${STAINLESS_MOCK_PORT:-}" ] && ! is_overriding_api_base_url ; then + export TEST_API_BASE_URL="http://127.0.0.1:$MOCK_PORT" + fi + + if [ "$RUN_SMOKE_TESTS" = true ]; then + echo -e "${YELLOW}==> Running smoke tests${NC}" + RUN_SMOKETESTS=1 ./node_modules/.bin/jest "${JEST_ARGS[@]}" + else + echo "==> Running tests" + ./node_modules/.bin/jest "${JEST_ARGS[@]}" + fi From 5229cff9696d7b5f34a643af2bce471bbbf1c213 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 23 Aug 2026 23:02:06 +0000 Subject: [PATCH 3/3] release: 1.30.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ package.json | 2 +- packages/mcp-server/manifest.json | 2 +- packages/mcp-server/package.json | 2 +- packages/mcp-server/src/server.ts | 2 +- src/version.ts | 2 +- 7 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6103afc2b..bacdd304e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.29.0" + ".": "1.30.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index bb12e4e7a..0f261f8d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.30.0 (2026-08-23) + +Full Changelog: [v1.29.0...v1.30.0](https://github.com/runloopai/api-client-ts/compare/v1.29.0...v1.30.0) + +### Features + +* **devboxes:** use optimistic create endpoint ([#825](https://github.com/runloopai/api-client-ts/issues/825)) ([07c0ca0](https://github.com/runloopai/api-client-ts/commit/07c0ca079a3ed09d2350d320323b616e471d0b03)) + + +### Chores + +* **internal:** allow the mock server port to be set with STAINLESS_MOCK_PORT ([627021b](https://github.com/runloopai/api-client-ts/commit/627021b4d35e9996fe00a7a263a8e8ab5a83cba5)) + ## 1.29.0 (2026-08-20) Full Changelog: [v1.28.0...v1.29.0](https://github.com/runloopai/api-client-ts/compare/v1.28.0...v1.29.0) diff --git a/package.json b/package.json index f534c35b2..b63e373a6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@runloop/api-client", - "version": "1.29.0", + "version": "1.30.0", "description": "The official TypeScript library for the Runloop API", "author": "Runloop ", "types": "dist/sdk.d.ts", diff --git a/packages/mcp-server/manifest.json b/packages/mcp-server/manifest.json index 9be530795..ab80a572f 100644 --- a/packages/mcp-server/manifest.json +++ b/packages/mcp-server/manifest.json @@ -1,7 +1,7 @@ { "dxt_version": "0.2", "name": "@runloop/api-client-mcp", - "version": "1.29.0", + "version": "1.30.0", "description": "The official MCP Server for the Runloop API", "author": { "name": "Runloop", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 4791bec49..7f1f2c14a 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "@runloop/api-client-mcp", - "version": "1.29.0", + "version": "1.30.0", "description": "The official MCP Server for the Runloop API", "author": "Runloop ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 8ba74e597..882090e63 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -16,7 +16,7 @@ export const newMcpServer = async (stainlessApiKey: string | undefined) => new McpServer( { name: 'runloop_api_client_api', - version: '1.29.0', + version: '1.30.0', }, { instructions: await getInstructions(stainlessApiKey), diff --git a/src/version.ts b/src/version.ts index ec0d2ee29..1fb715e33 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '1.29.0'; // x-release-please-version +export const VERSION = '1.30.0'; // x-release-please-version