Skip to content

Commit 55d1f93

Browse files
feat(client): add withOptions helper
1 parent f54f0a0 commit 55d1f93

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

src/client.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,23 @@ export class Stainless {
171171
this.apiKey = apiKey;
172172
}
173173

174+
/**
175+
* Create a new client instance re-using the same options given to the current client with optional overriding.
176+
*/
177+
withOptions(options: Partial<ClientOptions>): this {
178+
return new (this.constructor as any as new (props: ClientOptions) => typeof this)({
179+
...this._options,
180+
baseURL: this.baseURL,
181+
maxRetries: this.maxRetries,
182+
timeout: this.timeout,
183+
logger: this.logger,
184+
logLevel: this.logLevel,
185+
fetchOptions: this.fetchOptions,
186+
apiKey: this.apiKey,
187+
...options,
188+
});
189+
}
190+
174191
protected defaultQuery(): Record<string, string | undefined> | undefined {
175192
return this._options.defaultQuery;
176193
}

tests/index.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,82 @@ describe('instantiate client', () => {
325325
expect(client2.maxRetries).toEqual(2);
326326
});
327327

328+
describe('withOptions', () => {
329+
test('creates a new client with overridden options', () => {
330+
const client = new Stainless({
331+
baseURL: 'http://localhost:5000/',
332+
maxRetries: 3,
333+
apiKey: 'My API Key',
334+
});
335+
336+
const newClient = client.withOptions({
337+
maxRetries: 5,
338+
baseURL: 'http://localhost:5001/',
339+
});
340+
341+
// Verify the new client has updated options
342+
expect(newClient.maxRetries).toEqual(5);
343+
expect(newClient.baseURL).toEqual('http://localhost:5001/');
344+
345+
// Verify the original client is unchanged
346+
expect(client.maxRetries).toEqual(3);
347+
expect(client.baseURL).toEqual('http://localhost:5000/');
348+
349+
// Verify it's a different instance
350+
expect(newClient).not.toBe(client);
351+
expect(newClient.constructor).toBe(client.constructor);
352+
});
353+
354+
test('inherits options from the parent client', () => {
355+
const client = new Stainless({
356+
baseURL: 'http://localhost:5000/',
357+
defaultHeaders: { 'X-Test-Header': 'test-value' },
358+
defaultQuery: { 'test-param': 'test-value' },
359+
apiKey: 'My API Key',
360+
});
361+
362+
const newClient = client.withOptions({
363+
baseURL: 'http://localhost:5001/',
364+
});
365+
366+
// Test inherited options remain the same
367+
expect(newClient.buildURL('/foo', null)).toEqual('http://localhost:5001/foo?test-param=test-value');
368+
369+
const { req } = newClient.buildRequest({ path: '/foo', method: 'get' });
370+
expect(req.headers.get('x-test-header')).toEqual('test-value');
371+
});
372+
373+
test('respects runtime property changes when creating new client', () => {
374+
const client = new Stainless({
375+
baseURL: 'http://localhost:5000/',
376+
timeout: 1000,
377+
apiKey: 'My API Key',
378+
});
379+
380+
// Modify the client properties directly after creation
381+
client.baseURL = 'http://localhost:6000/';
382+
client.timeout = 2000;
383+
384+
// Create a new client with withOptions
385+
const newClient = client.withOptions({
386+
maxRetries: 10,
387+
});
388+
389+
// Verify the new client uses the updated properties, not the original ones
390+
expect(newClient.baseURL).toEqual('http://localhost:6000/');
391+
expect(newClient.timeout).toEqual(2000);
392+
expect(newClient.maxRetries).toEqual(10);
393+
394+
// Original client should still have its modified properties
395+
expect(client.baseURL).toEqual('http://localhost:6000/');
396+
expect(client.timeout).toEqual(2000);
397+
expect(client.maxRetries).not.toEqual(10);
398+
399+
// Verify URL building uses the updated baseURL
400+
expect(newClient.buildURL('/bar', null)).toEqual('http://localhost:6000/bar');
401+
});
402+
});
403+
328404
test('with environment variable arguments', () => {
329405
// set options via env var
330406
process.env['API_KEY'] = 'My API Key';

0 commit comments

Comments
 (0)