Skip to content

Commit ee079a4

Browse files
committed
feat: support API versioning
1 parent df4e35d commit ee079a4

File tree

2 files changed

+36
-18
lines changed

2 files changed

+36
-18
lines changed

src/core.ts

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ export class APIPromise<T> extends Promise<T> {
170170

171171
export abstract class APIClient {
172172
baseURL: string;
173+
apiVersion: string;
173174
maxRetries: number;
174175
timeout: number;
175176
httpAgent: Agent | undefined;
@@ -179,18 +180,21 @@ export abstract class APIClient {
179180

180181
constructor({
181182
baseURL,
183+
apiVersion,
182184
maxRetries = 2,
183185
timeout = 60000, // 1 minute
184186
httpAgent,
185187
fetch: overriddenFetch,
186188
}: {
187189
baseURL: string;
190+
apiVersion: string;
188191
maxRetries?: number | undefined;
189192
timeout: number | undefined;
190193
httpAgent: Agent | undefined;
191194
fetch: Fetch | undefined;
192195
}) {
193196
this.baseURL = baseURL;
197+
this.apiVersion = apiVersion;
194198
this.maxRetries = validatePositiveInteger('maxRetries', maxRetries);
195199
this.timeout = validatePositiveInteger('timeout', timeout);
196200
this.httpAgent = httpAgent;
@@ -215,6 +219,7 @@ export abstract class APIClient {
215219
Accept: 'application/json',
216220
'Content-Type': 'application/json',
217221
'User-Agent': this.getUserAgent(),
222+
'api-version': this.getAPIVerson(),
218223
...getPlatformHeaders(),
219224
...this.authHeaders(opts),
220225
};
@@ -225,7 +230,7 @@ export abstract class APIClient {
225230
/**
226231
* Override this to add your own headers validation:
227232
*/
228-
protected validateHeaders(headers: Headers, customHeaders: Headers) {}
233+
protected validateHeaders(headers: Headers, customHeaders: Headers) { }
229234

230235
protected defaultIdempotencyKey(): string {
231236
return `stainless-node-retry-${uuid4()}`;
@@ -260,10 +265,10 @@ export abstract class APIClient {
260265
Promise.resolve(opts).then(async (opts) => {
261266
const body =
262267
opts && isBlobLike(opts?.body) ? new DataView(await opts.body.arrayBuffer())
263-
: opts?.body instanceof DataView ? opts.body
264-
: opts?.body instanceof ArrayBuffer ? new DataView(opts.body)
265-
: opts && ArrayBuffer.isView(opts?.body) ? new DataView(opts.body.buffer)
266-
: opts?.body;
268+
: opts?.body instanceof DataView ? opts.body
269+
: opts?.body instanceof ArrayBuffer ? new DataView(opts.body)
270+
: opts && ArrayBuffer.isView(opts?.body) ? new DataView(opts.body.buffer)
271+
: opts?.body;
267272
return { method, path, ...opts, body };
268273
}),
269274
);
@@ -305,9 +310,9 @@ export abstract class APIClient {
305310
const body =
306311
ArrayBuffer.isView(options.body) || (options.__binaryRequest && typeof options.body === 'string') ?
307312
options.body
308-
: isMultipartBody(options.body) ? options.body.body
309-
: options.body ? JSON.stringify(options.body, null, 2)
310-
: null;
313+
: isMultipartBody(options.body) ? options.body.body
314+
: options.body ? JSON.stringify(options.body, null, 2)
315+
: null;
311316
const contentLength = this.calculateContentLength(body);
312317

313318
const url = this.buildURL(path!, query);
@@ -396,7 +401,7 @@ export abstract class APIClient {
396401
/**
397402
* Used as a callback for mutating the given `FinalRequestOptions` object.
398403
*/
399-
protected async prepareOptions(options: FinalRequestOptions): Promise<void> {}
404+
protected async prepareOptions(options: FinalRequestOptions): Promise<void> { }
400405

401406
/**
402407
* Used as a callback for mutating the given `RequestInit` object.
@@ -407,14 +412,14 @@ export abstract class APIClient {
407412
protected async prepareRequest(
408413
request: RequestInit,
409414
{ url, options }: { url: string; options: FinalRequestOptions },
410-
): Promise<void> {}
415+
): Promise<void> { }
411416

412417
protected parseHeaders(headers: HeadersInit | null | undefined): Record<string, string> {
413418
return (
414419
!headers ? {}
415-
: Symbol.iterator in headers ?
416-
Object.fromEntries(Array.from(headers as Iterable<string[]>).map((header) => [...header]))
417-
: { ...(headers as any as Record<string, string>) }
420+
: Symbol.iterator in headers ?
421+
Object.fromEntries(Array.from(headers as Iterable<string[]>).map((header) => [...header]))
422+
: { ...(headers as any as Record<string, string>) }
418423
);
419424
}
420425

@@ -507,7 +512,7 @@ export abstract class APIClient {
507512
const url =
508513
isAbsoluteURL(path) ?
509514
new URL(path)
510-
: new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
515+
: new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
511516

512517
const defaultQuery = this.defaultQuery();
513518
if (!isEmptyObj(defaultQuery)) {
@@ -646,6 +651,10 @@ export abstract class APIClient {
646651
private getUserAgent(): string {
647652
return `${this.constructor.name}/JS ${VERSION}`;
648653
}
654+
655+
private getAPIVerson(): string {
656+
return this.apiVersion;
657+
}
649658
}
650659

651660
export type PageInfo = { url: URL } | { params: Record<string, unknown> | null };
@@ -728,9 +737,9 @@ export abstract class AbstractPage<Item> implements AsyncIterable<Item> {
728737
* }
729738
*/
730739
export class PagePromise<
731-
PageClass extends AbstractPage<Item>,
732-
Item = ReturnType<PageClass['getPaginatedItems']>[number],
733-
>
740+
PageClass extends AbstractPage<Item>,
741+
Item = ReturnType<PageClass['getPaginatedItems']>[number],
742+
>
734743
extends APIPromise<PageClass>
735744
implements AsyncIterable<Item>
736745
{
@@ -1030,7 +1039,7 @@ export const castToError = (err: any): Error => {
10301039
if (typeof err === 'object' && err !== null) {
10311040
try {
10321041
return new Error(JSON.stringify(err));
1033-
} catch {}
1042+
} catch { }
10341043
}
10351044
return new Error(err);
10361045
};

src/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ export interface ClientOptions {
141141
*/
142142
baseURL?: string | null | undefined;
143143

144+
/**
145+
* Define the API version to target for the requests, e.g., "2025-01-01"
146+
*/
147+
apiVersion?: string | null;
148+
144149
/**
145150
* The maximum amount of time (in milliseconds) that the client should wait for a response
146151
* from the server before timing out a single request.
@@ -210,6 +215,7 @@ export class Cloudflare extends Core.APIClient {
210215
* @param {string | null | undefined} [opts.apiEmail=process.env['CLOUDFLARE_EMAIL'] ?? null]
211216
* @param {string | null | undefined} [opts.userServiceKey=process.env['CLOUDFLARE_API_USER_SERVICE_KEY'] ?? null]
212217
* @param {string} [opts.baseURL=process.env['CLOUDFLARE_BASE_URL'] ?? https://api.cloudflare.com/client/v4] - Override the default base URL for the API.
218+
* @param {string | null} [opts.apiVersion] - Define the version to target for the API.
213219
* @param {number} [opts.timeout=1 minute] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
214220
* @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.
215221
* @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.
@@ -219,6 +225,7 @@ export class Cloudflare extends Core.APIClient {
219225
*/
220226
constructor({
221227
baseURL = Core.readEnv('CLOUDFLARE_BASE_URL'),
228+
apiVersion = null,
222229
apiToken = Core.readEnv('CLOUDFLARE_API_TOKEN') ?? null,
223230
apiKey = Core.readEnv('CLOUDFLARE_API_KEY') ?? null,
224231
apiEmail = Core.readEnv('CLOUDFLARE_EMAIL') ?? null,
@@ -232,10 +239,12 @@ export class Cloudflare extends Core.APIClient {
232239
userServiceKey,
233240
...opts,
234241
baseURL: baseURL || `https://api.cloudflare.com/client/v4`,
242+
apiVersion: apiVersion || new Date().toISOString().slice(0, 10),
235243
};
236244

237245
super({
238246
baseURL: options.baseURL!,
247+
apiVersion: options.apiVersion!,
239248
timeout: options.timeout ?? 60000 /* 1 minute */,
240249
httpAgent: options.httpAgent,
241250
maxRetries: options.maxRetries,

0 commit comments

Comments
 (0)