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..762e97925 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.30.0 (2026-08-20) + +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)) + ## 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/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/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 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(); });