diff --git a/src/sdk/devbox.ts b/src/sdk/devbox.ts index df25963c9..e34a938d3 100644 --- a/src/sdk/devbox.ts +++ b/src/sdk/devbox.ts @@ -838,7 +838,9 @@ export class Devbox { if (!tunnel) { throw new RunloopError('No tunnel has been enabled for this devbox. Call net.enableTunnel() first.'); } - return `https://${port}-${tunnel.tunnel_key}.tunnel.runloop.ai`; + const apiHost = new URL(this.client.baseURL).hostname; + const baseDomain = apiHost.startsWith('api.') ? apiHost.slice(4) : apiHost; + return `https://${port}-${tunnel.tunnel_key}.tunnel.${baseDomain}`; } /** diff --git a/tests/objects/devbox.test.ts b/tests/objects/devbox.test.ts index 4a9fadfa9..2cb930c97 100644 --- a/tests/objects/devbox.test.ts +++ b/tests/objects/devbox.test.ts @@ -11,6 +11,7 @@ describe('Devbox (New API)', () => { beforeEach(() => { // Create mock client instance with proper structure mockClient = { + baseURL: 'https://api.runloop.ai', devboxes: { createAndAwaitRunning: jest.fn(), retrieve: jest.fn(), @@ -303,6 +304,24 @@ describe('Devbox (New API)', () => { expect(url).toBe('https://3000-mykey456.tunnel.runloop.ai'); }); + it('should derive tunnel domain from client baseURL', async () => { + const mockTunnel = { + tunnel_key: 'abc123xyz', + auth_mode: 'open' as const, + create_time_ms: Date.now(), + }; + const dataWithTunnel = { ...mockDevboxData, tunnel: mockTunnel }; + mockClient.devboxes.retrieve.mockResolvedValue(dataWithTunnel); + + mockClient.baseURL = 'https://api.runloop.pro'; + expect(await devbox.getTunnelUrl(8080)).toBe('https://8080-abc123xyz.tunnel.runloop.pro'); + + mockClient.baseURL = 'http://127.0.0.1:8080'; + expect(await devbox.getTunnelUrl(8080)).toBe('https://8080-abc123xyz.tunnel.127.0.0.1'); + + mockClient.baseURL = 'https://api.runloop.ai'; + }); + it('should throw RunloopError when no tunnel has been enabled', async () => { const dataWithoutTunnel = { ...mockDevboxData, tunnel: null }; mockClient.devboxes.retrieve.mockResolvedValue(dataWithoutTunnel); diff --git a/tests/smoketests/object-oriented/devbox.test.ts b/tests/smoketests/object-oriented/devbox.test.ts index 603128f30..8d8598cbd 100644 --- a/tests/smoketests/object-oriented/devbox.test.ts +++ b/tests/smoketests/object-oriented/devbox.test.ts @@ -413,10 +413,10 @@ describe('smoketest: object-oriented devbox', () => { expect(tunnel.tunnel_key).toBeTruthy(); const url = await devbox.getTunnelUrl(8080); - expect(url).toBe(`https://8080-${tunnel.tunnel_key}.tunnel.runloop.ai`); + expect(url).toContain(`https://8080-${tunnel.tunnel_key}.tunnel.runloop.`); const url3000 = await devbox.getTunnelUrl(3000); - expect(url3000).toBe(`https://3000-${tunnel.tunnel_key}.tunnel.runloop.ai`); + expect(url3000).toContain(`https://3000-${tunnel.tunnel_key}.tunnel.runloop.`); } finally { await devbox.shutdown(); }