@lorikeetai/node-sdk 0.1.0-beta.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +11 -11
  3. package/_shims/MultipartBody.js.map +1 -1
  4. package/_shims/MultipartBody.mjs.map +1 -1
  5. package/_shims/auto/runtime-bun.d.ts.map +1 -1
  6. package/_shims/auto/runtime-bun.js.map +1 -1
  7. package/_shims/auto/runtime-node.d.ts.map +1 -1
  8. package/_shims/auto/runtime-node.js.map +1 -1
  9. package/_shims/auto/runtime.d.ts.map +1 -1
  10. package/_shims/auto/runtime.js.map +1 -1
  11. package/_shims/auto/types-node.d.ts.map +1 -1
  12. package/_shims/auto/types-node.js.map +1 -1
  13. package/_shims/auto/types.d.ts +52 -52
  14. package/_shims/bun-runtime.d.ts.map +1 -1
  15. package/_shims/bun-runtime.js.map +1 -1
  16. package/_shims/bun-runtime.mjs.map +1 -1
  17. package/_shims/index.d.ts +36 -36
  18. package/_shims/index.js +5 -5
  19. package/_shims/index.mjs +4 -4
  20. package/_shims/node-runtime.d.ts.map +1 -1
  21. package/_shims/node-runtime.js.map +1 -1
  22. package/_shims/node-runtime.mjs.map +1 -1
  23. package/_shims/node-types.d.ts +27 -27
  24. package/_shims/registry.d.ts.map +1 -1
  25. package/_shims/registry.js.map +1 -1
  26. package/_shims/registry.mjs.map +1 -1
  27. package/_shims/web-runtime.d.ts.map +1 -1
  28. package/_shims/web-runtime.js.map +1 -1
  29. package/_shims/web-runtime.mjs.map +1 -1
  30. package/_shims/web-types.d.ts +52 -52
  31. package/core.d.ts.map +1 -1
  32. package/core.js +0 -1
  33. package/core.js.map +1 -1
  34. package/core.mjs +0 -1
  35. package/core.mjs.map +1 -1
  36. package/error.d.ts.map +1 -1
  37. package/error.js.map +1 -1
  38. package/error.mjs.map +1 -1
  39. package/index.d.mts +3 -0
  40. package/index.d.ts +3 -0
  41. package/index.d.ts.map +1 -1
  42. package/index.js +3 -0
  43. package/index.js.map +1 -1
  44. package/index.mjs +3 -0
  45. package/index.mjs.map +1 -1
  46. package/lib/generate-signature.js.map +1 -1
  47. package/lib/generate-signature.mjs.map +1 -1
  48. package/package.json +1 -1
  49. package/resource.d.ts.map +1 -1
  50. package/resource.js.map +1 -1
  51. package/resource.mjs.map +1 -1
  52. package/resources/conversation/chat.d.ts +9 -5
  53. package/resources/conversation/chat.d.ts.map +1 -1
  54. package/resources/conversation/chat.js +3 -3
  55. package/resources/conversation/chat.js.map +1 -1
  56. package/resources/conversation/chat.mjs +3 -3
  57. package/resources/conversation/chat.mjs.map +1 -1
  58. package/resources/conversation/conversation.d.ts.map +1 -1
  59. package/resources/conversation/conversation.js.map +1 -1
  60. package/resources/conversation/conversation.mjs.map +1 -1
  61. package/resources/conversation/email.d.ts +6 -2
  62. package/resources/conversation/email.d.ts.map +1 -1
  63. package/resources/conversation/email.js +1 -1
  64. package/resources/conversation/email.js.map +1 -1
  65. package/resources/conversation/email.mjs +1 -1
  66. package/resources/conversation/email.mjs.map +1 -1
  67. package/resources/conversation/index.d.ts.map +1 -1
  68. package/resources/conversation/index.js.map +1 -1
  69. package/resources/customer.d.ts +61 -0
  70. package/resources/customer.d.ts.map +1 -0
  71. package/resources/customer.js +12 -0
  72. package/resources/customer.js.map +1 -0
  73. package/resources/customer.mjs +8 -0
  74. package/resources/customer.mjs.map +1 -0
  75. package/resources/index.d.ts +1 -0
  76. package/resources/index.d.ts.map +1 -1
  77. package/resources/index.js +3 -1
  78. package/resources/index.js.map +1 -1
  79. package/resources/index.mjs +1 -0
  80. package/resources/index.mjs.map +1 -1
  81. package/resources/ingest.d.ts.map +1 -1
  82. package/resources/ingest.js.map +1 -1
  83. package/resources/ingest.mjs.map +1 -1
  84. package/resources/token.d.ts.map +1 -1
  85. package/resources/token.js.map +1 -1
  86. package/resources/token.mjs.map +1 -1
  87. package/shims/node.d.ts.map +1 -1
  88. package/shims/node.js.map +1 -1
  89. package/shims/node.mjs.map +1 -1
  90. package/shims/web.d.ts.map +1 -1
  91. package/shims/web.js.map +1 -1
  92. package/shims/web.mjs.map +1 -1
  93. package/src/_shims/MultipartBody.ts +1 -1
  94. package/src/_shims/auto/runtime-bun.ts +1 -1
  95. package/src/_shims/auto/runtime-node.ts +1 -1
  96. package/src/_shims/auto/runtime.ts +1 -1
  97. package/src/_shims/auto/types-node.ts +1 -1
  98. package/src/_shims/auto/types.d.ts +52 -52
  99. package/src/_shims/bun-runtime.ts +6 -6
  100. package/src/_shims/index.d.ts +36 -36
  101. package/src/_shims/index.js +5 -5
  102. package/src/_shims/index.mjs +4 -4
  103. package/src/_shims/node-runtime.ts +32 -32
  104. package/src/_shims/node-types.d.ts +27 -27
  105. package/src/_shims/registry.ts +44 -44
  106. package/src/_shims/web-runtime.ts +16 -16
  107. package/src/_shims/web-types.d.ts +52 -52
  108. package/src/core.ts +372 -372
  109. package/src/error.ts +37 -37
  110. package/src/index.ts +74 -65
  111. package/src/lib/generate-signature.ts +3 -3
  112. package/src/resource.ts +3 -3
  113. package/src/resources/conversation/chat.ts +23 -18
  114. package/src/resources/conversation/conversation.ts +11 -11
  115. package/src/resources/conversation/email.ts +12 -7
  116. package/src/resources/conversation/index.ts +3 -3
  117. package/src/resources/customer.ts +81 -0
  118. package/src/resources/index.ts +4 -3
  119. package/src/resources/ingest.ts +7 -7
  120. package/src/resources/token.ts +9 -9
  121. package/src/shims/node.ts +24 -24
  122. package/src/shims/web.ts +24 -24
  123. package/src/uploads.ts +72 -72
  124. package/src/version.ts +1 -1
  125. package/uploads.d.ts.map +1 -1
  126. package/uploads.js.map +1 -1
  127. package/uploads.mjs.map +1 -1
  128. package/version.d.ts +1 -1
  129. package/version.d.ts.map +1 -1
  130. package/version.js +1 -1
  131. package/version.js.map +1 -1
  132. package/version.mjs +1 -1
  133. package/version.mjs.map +1 -1
package/src/core.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { VERSION } from './version'
1
+ import { VERSION } from './version';
2
2
  import {
3
3
  LorikeetError,
4
4
  APIError,
5
5
  APIConnectionError,
6
6
  APIConnectionTimeoutError,
7
7
  APIUserAbortError,
8
- } from './error'
8
+ } from './error';
9
9
  import {
10
10
  kind as shimsKind,
11
11
  type Readable,
@@ -16,53 +16,53 @@ import {
16
16
  type RequestInit,
17
17
  type Response,
18
18
  type HeadersInit,
19
- } from './_shims/index'
20
- export { type Response }
21
- import { BlobLike, isBlobLike, isMultipartBody } from './uploads'
19
+ } from './_shims/index';
20
+ export { type Response };
21
+ import { BlobLike, isBlobLike, isMultipartBody } from './uploads';
22
22
  export {
23
23
  maybeMultipartFormRequestOptions,
24
24
  multipartFormRequestOptions,
25
25
  createForm,
26
26
  type Uploadable,
27
- } from './uploads'
27
+ } from './uploads';
28
28
 
29
- export type Fetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>
29
+ export type Fetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
30
30
 
31
- type PromiseOrValue<T> = T | Promise<T>
31
+ type PromiseOrValue<T> = T | Promise<T>;
32
32
 
33
33
  type APIResponseProps = {
34
- response: Response
35
- options: FinalRequestOptions
36
- controller: AbortController
37
- }
34
+ response: Response;
35
+ options: FinalRequestOptions;
36
+ controller: AbortController;
37
+ };
38
38
 
39
39
  async function defaultParseResponse<T>(props: APIResponseProps): Promise<T> {
40
- const { response } = props
40
+ const { response } = props;
41
41
  // fetch refuses to read the body when the status code is 204.
42
42
  if (response.status === 204) {
43
- return null as T
43
+ return null as T;
44
44
  }
45
45
 
46
46
  if (props.options.__binaryResponse) {
47
- return response as unknown as T
47
+ return response as unknown as T;
48
48
  }
49
49
 
50
- const contentType = response.headers.get('content-type')
50
+ const contentType = response.headers.get('content-type');
51
51
  const isJSON =
52
- contentType?.includes('application/json') || contentType?.includes('application/vnd.api+json')
52
+ contentType?.includes('application/json') || contentType?.includes('application/vnd.api+json');
53
53
  if (isJSON) {
54
- const json = await response.json()
54
+ const json = await response.json();
55
55
 
56
- debug('response', response.status, response.url, response.headers, json)
56
+ debug('response', response.status, response.url, response.headers, json);
57
57
 
58
- return json as T
58
+ return json as T;
59
59
  }
60
60
 
61
- const text = await response.text()
62
- debug('response', response.status, response.url, response.headers, text)
61
+ const text = await response.text();
62
+ debug('response', response.status, response.url, response.headers, text);
63
63
 
64
64
  // TODO handle blob, arraybuffer, other content types, etc.
65
- return text as unknown as T
65
+ return text as unknown as T;
66
66
  }
67
67
 
68
68
  /**
@@ -70,7 +70,7 @@ async function defaultParseResponse<T>(props: APIResponseProps): Promise<T> {
70
70
  * for interacting with the SDK.
71
71
  */
72
72
  export class APIPromise<T> extends Promise<T> {
73
- private parsedPromise: Promise<T> | undefined
73
+ private parsedPromise: Promise<T> | undefined;
74
74
 
75
75
  constructor(
76
76
  private responsePromise: Promise<APIResponseProps>,
@@ -80,14 +80,14 @@ export class APIPromise<T> extends Promise<T> {
80
80
  // this is maybe a bit weird but this has to be a no-op to not implicitly
81
81
  // parse the response body; instead .then, .catch, .finally are overridden
82
82
  // to parse the response
83
- resolve(null as any)
84
- })
83
+ resolve(null as any);
84
+ });
85
85
  }
86
86
 
87
87
  _thenUnwrap<U>(transform: (data: T, props: APIResponseProps) => U): APIPromise<U> {
88
88
  return new APIPromise(this.responsePromise, async (props) =>
89
89
  transform(await this.parseResponse(props), props),
90
- )
90
+ );
91
91
  }
92
92
 
93
93
  /**
@@ -104,7 +104,7 @@ export class APIPromise<T> extends Promise<T> {
104
104
  * - `import '@lorikeetai/node-sdk/shims/web'` (otherwise)
105
105
  */
106
106
  asResponse(): Promise<Response> {
107
- return this.responsePromise.then((p) => p.response)
107
+ return this.responsePromise.then((p) => p.response);
108
108
  }
109
109
  /**
110
110
  * Gets the parsed response data and the raw `Response` instance.
@@ -120,43 +120,43 @@ export class APIPromise<T> extends Promise<T> {
120
120
  * - `import '@lorikeetai/node-sdk/shims/web'` (otherwise)
121
121
  */
122
122
  async withResponse(): Promise<{ data: T; response: Response }> {
123
- const [data, response] = await Promise.all([this.parse(), this.asResponse()])
124
- return { data, response }
123
+ const [data, response] = await Promise.all([this.parse(), this.asResponse()]);
124
+ return { data, response };
125
125
  }
126
126
 
127
127
  private parse(): Promise<T> {
128
128
  if (!this.parsedPromise) {
129
- this.parsedPromise = this.responsePromise.then(this.parseResponse)
129
+ this.parsedPromise = this.responsePromise.then(this.parseResponse);
130
130
  }
131
- return this.parsedPromise
131
+ return this.parsedPromise;
132
132
  }
133
133
 
134
134
  override then<TResult1 = T, TResult2 = never>(
135
135
  onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
136
136
  onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null,
137
137
  ): Promise<TResult1 | TResult2> {
138
- return this.parse().then(onfulfilled, onrejected)
138
+ return this.parse().then(onfulfilled, onrejected);
139
139
  }
140
140
 
141
141
  override catch<TResult = never>(
142
142
  onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null,
143
143
  ): Promise<T | TResult> {
144
- return this.parse().catch(onrejected)
144
+ return this.parse().catch(onrejected);
145
145
  }
146
146
 
147
147
  override finally(onfinally?: (() => void) | undefined | null): Promise<T> {
148
- return this.parse().finally(onfinally)
148
+ return this.parse().finally(onfinally);
149
149
  }
150
150
  }
151
151
 
152
152
  export abstract class APIClient {
153
- baseURL: string
154
- maxRetries: number
155
- timeout: number
156
- httpAgent: Agent | undefined
153
+ baseURL: string;
154
+ maxRetries: number;
155
+ timeout: number;
156
+ httpAgent: Agent | undefined;
157
157
 
158
- private fetch: Fetch
159
- protected idempotencyHeader?: string
158
+ private fetch: Fetch;
159
+ protected idempotencyHeader?: string;
160
160
 
161
161
  constructor({
162
162
  baseURL,
@@ -165,22 +165,22 @@ export abstract class APIClient {
165
165
  httpAgent,
166
166
  fetch: overridenFetch,
167
167
  }: {
168
- baseURL: string
169
- maxRetries?: number | undefined
170
- timeout: number | undefined
171
- httpAgent: Agent | undefined
172
- fetch: Fetch | undefined
168
+ baseURL: string;
169
+ maxRetries?: number | undefined;
170
+ timeout: number | undefined;
171
+ httpAgent: Agent | undefined;
172
+ fetch: Fetch | undefined;
173
173
  }) {
174
- this.baseURL = baseURL
175
- this.maxRetries = validatePositiveInteger('maxRetries', maxRetries)
176
- this.timeout = validatePositiveInteger('timeout', timeout)
177
- this.httpAgent = httpAgent
174
+ this.baseURL = baseURL;
175
+ this.maxRetries = validatePositiveInteger('maxRetries', maxRetries);
176
+ this.timeout = validatePositiveInteger('timeout', timeout);
177
+ this.httpAgent = httpAgent;
178
178
 
179
- this.fetch = overridenFetch ?? fetch
179
+ this.fetch = overridenFetch ?? fetch;
180
180
  }
181
181
 
182
182
  protected authHeaders(opts: FinalRequestOptions): Headers {
183
- return {}
183
+ return {};
184
184
  }
185
185
 
186
186
  /**
@@ -198,10 +198,10 @@ export abstract class APIClient {
198
198
  'User-Agent': this.getUserAgent(),
199
199
  ...getPlatformHeaders(),
200
200
  ...this.authHeaders(opts),
201
- }
201
+ };
202
202
  }
203
203
 
204
- protected abstract defaultQuery(): DefaultQuery | undefined
204
+ protected abstract defaultQuery(): DefaultQuery | undefined;
205
205
 
206
206
  /**
207
207
  * Override this to add your own headers validation:
@@ -209,27 +209,27 @@ export abstract class APIClient {
209
209
  protected validateHeaders(headers: Headers, customHeaders: Headers) {}
210
210
 
211
211
  protected defaultIdempotencyKey(): string {
212
- return `stainless-node-retry-${uuid4()}`
212
+ return `stainless-node-retry-${uuid4()}`;
213
213
  }
214
214
 
215
215
  get<Req, Rsp>(path: string, opts?: PromiseOrValue<RequestOptions<Req>>): APIPromise<Rsp> {
216
- return this.methodRequest('get', path, opts)
216
+ return this.methodRequest('get', path, opts);
217
217
  }
218
218
 
219
219
  post<Req, Rsp>(path: string, opts?: PromiseOrValue<RequestOptions<Req>>): APIPromise<Rsp> {
220
- return this.methodRequest('post', path, opts)
220
+ return this.methodRequest('post', path, opts);
221
221
  }
222
222
 
223
223
  patch<Req, Rsp>(path: string, opts?: PromiseOrValue<RequestOptions<Req>>): APIPromise<Rsp> {
224
- return this.methodRequest('patch', path, opts)
224
+ return this.methodRequest('patch', path, opts);
225
225
  }
226
226
 
227
227
  put<Req, Rsp>(path: string, opts?: PromiseOrValue<RequestOptions<Req>>): APIPromise<Rsp> {
228
- return this.methodRequest('put', path, opts)
228
+ return this.methodRequest('put', path, opts);
229
229
  }
230
230
 
231
231
  delete<Req, Rsp>(path: string, opts?: PromiseOrValue<RequestOptions<Req>>): APIPromise<Rsp> {
232
- return this.methodRequest('delete', path, opts)
232
+ return this.methodRequest('delete', path, opts);
233
233
  }
234
234
 
235
235
  private methodRequest<Req, Rsp>(
@@ -244,10 +244,10 @@ export abstract class APIClient {
244
244
  : opts?.body instanceof DataView ? opts.body
245
245
  : opts?.body instanceof ArrayBuffer ? new DataView(opts.body)
246
246
  : opts && ArrayBuffer.isView(opts?.body) ? new DataView(opts.body.buffer)
247
- : opts?.body
248
- return { method, path, ...opts, body }
247
+ : opts?.body;
248
+ return { method, path, ...opts, body };
249
249
  }),
250
- )
250
+ );
251
251
  }
252
252
 
253
253
  getAPIList<Item, PageClass extends AbstractPage<Item> = AbstractPage<Item>>(
@@ -255,46 +255,46 @@ export abstract class APIClient {
255
255
  Page: new (...args: any[]) => PageClass,
256
256
  opts?: RequestOptions<any>,
257
257
  ): PagePromise<PageClass, Item> {
258
- return this.requestAPIList(Page, { method: 'get', path, ...opts })
258
+ return this.requestAPIList(Page, { method: 'get', path, ...opts });
259
259
  }
260
260
 
261
261
  private calculateContentLength(body: unknown): string | null {
262
262
  if (typeof body === 'string') {
263
263
  if (typeof Buffer !== 'undefined') {
264
- return Buffer.byteLength(body, 'utf8').toString()
264
+ return Buffer.byteLength(body, 'utf8').toString();
265
265
  }
266
266
 
267
267
  if (typeof TextEncoder !== 'undefined') {
268
- const encoder = new TextEncoder()
269
- const encoded = encoder.encode(body)
270
- return encoded.length.toString()
268
+ const encoder = new TextEncoder();
269
+ const encoded = encoder.encode(body);
270
+ return encoded.length.toString();
271
271
  }
272
272
  } else if (ArrayBuffer.isView(body)) {
273
- return body.byteLength.toString()
273
+ return body.byteLength.toString();
274
274
  }
275
275
 
276
- return null
276
+ return null;
277
277
  }
278
278
 
279
279
  buildRequest<Req>(
280
280
  options: FinalRequestOptions<Req>,
281
281
  { retryCount = 0 }: { retryCount?: number } = {},
282
282
  ): { req: RequestInit; url: string; timeout: number } {
283
- const { method, path, query, headers: headers = {} } = options
283
+ const { method, path, query, headers: headers = {} } = options;
284
284
 
285
285
  const body =
286
286
  ArrayBuffer.isView(options.body) || (options.__binaryRequest && typeof options.body === 'string') ?
287
287
  options.body
288
288
  : isMultipartBody(options.body) ? options.body.body
289
289
  : options.body ? JSON.stringify(options.body, null, 2)
290
- : null
291
- const contentLength = this.calculateContentLength(body)
292
-
293
- const url = this.buildURL(path!, query)
294
- if ('timeout' in options) validatePositiveInteger('timeout', options.timeout)
295
- const timeout = options.timeout ?? this.timeout
296
- const httpAgent = options.httpAgent ?? this.httpAgent ?? getDefaultAgent(url)
297
- const minAgentTimeout = timeout + 1000
290
+ : null;
291
+ const contentLength = this.calculateContentLength(body);
292
+
293
+ const url = this.buildURL(path!, query);
294
+ if ('timeout' in options) validatePositiveInteger('timeout', options.timeout);
295
+ const timeout = options.timeout ?? this.timeout;
296
+ const httpAgent = options.httpAgent ?? this.httpAgent ?? getDefaultAgent(url);
297
+ const minAgentTimeout = timeout + 1000;
298
298
  if (
299
299
  typeof (httpAgent as any)?.options?.timeout === 'number' &&
300
300
  minAgentTimeout > ((httpAgent as any).options.timeout ?? 0)
@@ -303,15 +303,15 @@ export abstract class APIClient {
303
303
  // This may seem strange, but leaking active sockets should be rare and not particularly problematic,
304
304
  // and without mutating agent we would need to create more of them.
305
305
  // This tradeoff optimizes for performance.
306
- ;(httpAgent as any).options.timeout = minAgentTimeout
306
+ (httpAgent as any).options.timeout = minAgentTimeout;
307
307
  }
308
308
 
309
309
  if (this.idempotencyHeader && method !== 'get') {
310
- if (!options.idempotencyKey) options.idempotencyKey = this.defaultIdempotencyKey()
311
- headers[this.idempotencyHeader] = options.idempotencyKey
310
+ if (!options.idempotencyKey) options.idempotencyKey = this.defaultIdempotencyKey();
311
+ headers[this.idempotencyHeader] = options.idempotencyKey;
312
312
  }
313
313
 
314
- const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount })
314
+ const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });
315
315
 
316
316
  const req: RequestInit = {
317
317
  method,
@@ -321,9 +321,9 @@ export abstract class APIClient {
321
321
  // @ts-ignore node-fetch uses a custom AbortSignal type that is
322
322
  // not compatible with standard web types
323
323
  signal: options.signal ?? null,
324
- }
324
+ };
325
325
 
326
- return { req, url, timeout }
326
+ return { req, url, timeout };
327
327
  }
328
328
 
329
329
  private buildHeaders({
@@ -332,23 +332,23 @@ export abstract class APIClient {
332
332
  contentLength,
333
333
  retryCount,
334
334
  }: {
335
- options: FinalRequestOptions
336
- headers: Record<string, string | null | undefined>
337
- contentLength: string | null | undefined
338
- retryCount: number
335
+ options: FinalRequestOptions;
336
+ headers: Record<string, string | null | undefined>;
337
+ contentLength: string | null | undefined;
338
+ retryCount: number;
339
339
  }): Record<string, string> {
340
- const reqHeaders: Record<string, string> = {}
340
+ const reqHeaders: Record<string, string> = {};
341
341
  if (contentLength) {
342
- reqHeaders['content-length'] = contentLength
342
+ reqHeaders['content-length'] = contentLength;
343
343
  }
344
344
 
345
- const defaultHeaders = this.defaultHeaders(options)
346
- applyHeadersMut(reqHeaders, defaultHeaders)
347
- applyHeadersMut(reqHeaders, headers)
345
+ const defaultHeaders = this.defaultHeaders(options);
346
+ applyHeadersMut(reqHeaders, defaultHeaders);
347
+ applyHeadersMut(reqHeaders, headers);
348
348
 
349
349
  // let builtin fetch set the Content-Type for multipart bodies
350
350
  if (isMultipartBody(options.body) && shimsKind !== 'node') {
351
- delete reqHeaders['content-type']
351
+ delete reqHeaders['content-type'];
352
352
  }
353
353
 
354
354
  // Don't set the retry count header if it was already set or removed through default headers or by the
@@ -358,12 +358,12 @@ export abstract class APIClient {
358
358
  getHeader(defaultHeaders, 'x-stainless-retry-count') === undefined &&
359
359
  getHeader(headers, 'x-stainless-retry-count') === undefined
360
360
  ) {
361
- reqHeaders['x-stainless-retry-count'] = String(retryCount)
361
+ reqHeaders['x-stainless-retry-count'] = String(retryCount);
362
362
  }
363
363
 
364
- this.validateHeaders(reqHeaders, headers)
364
+ this.validateHeaders(reqHeaders, headers);
365
365
 
366
- return reqHeaders
366
+ return reqHeaders;
367
367
  }
368
368
 
369
369
  /**
@@ -388,7 +388,7 @@ export abstract class APIClient {
388
388
  : Symbol.iterator in headers ?
389
389
  Object.fromEntries(Array.from(headers as Iterable<string[]>).map((header) => [...header]))
390
390
  : { ...headers }
391
- )
391
+ );
392
392
  }
393
393
 
394
394
  protected makeStatusError(
@@ -397,101 +397,101 @@ export abstract class APIClient {
397
397
  message: string | undefined,
398
398
  headers: Headers | undefined,
399
399
  ): APIError {
400
- return APIError.generate(status, error, message, headers)
400
+ return APIError.generate(status, error, message, headers);
401
401
  }
402
402
 
403
403
  request<Req, Rsp>(
404
404
  options: PromiseOrValue<FinalRequestOptions<Req>>,
405
405
  remainingRetries: number | null = null,
406
406
  ): APIPromise<Rsp> {
407
- return new APIPromise(this.makeRequest(options, remainingRetries))
407
+ return new APIPromise(this.makeRequest(options, remainingRetries));
408
408
  }
409
409
 
410
410
  private async makeRequest<Req>(
411
411
  optionsInput: PromiseOrValue<FinalRequestOptions<Req>>,
412
412
  retriesRemaining: number | null,
413
413
  ): Promise<APIResponseProps> {
414
- const options = await optionsInput
415
- const maxRetries = options.maxRetries ?? this.maxRetries
414
+ const options = await optionsInput;
415
+ const maxRetries = options.maxRetries ?? this.maxRetries;
416
416
  if (retriesRemaining == null) {
417
- retriesRemaining = maxRetries
417
+ retriesRemaining = maxRetries;
418
418
  }
419
419
 
420
- await this.prepareOptions(options)
420
+ await this.prepareOptions(options);
421
421
 
422
- const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining })
422
+ const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });
423
423
 
424
- await this.prepareRequest(req, { url, options })
424
+ await this.prepareRequest(req, { url, options });
425
425
 
426
- debug('request', url, options, req.headers)
426
+ debug('request', url, options, req.headers);
427
427
 
428
428
  if (options.signal?.aborted) {
429
- throw new APIUserAbortError()
429
+ throw new APIUserAbortError();
430
430
  }
431
431
 
432
- const controller = new AbortController()
433
- const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError)
432
+ const controller = new AbortController();
433
+ const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);
434
434
 
435
435
  if (response instanceof Error) {
436
436
  if (options.signal?.aborted) {
437
- throw new APIUserAbortError()
437
+ throw new APIUserAbortError();
438
438
  }
439
439
  if (retriesRemaining) {
440
- return this.retryRequest(options, retriesRemaining)
440
+ return this.retryRequest(options, retriesRemaining);
441
441
  }
442
442
  if (response.name === 'AbortError') {
443
- throw new APIConnectionTimeoutError()
443
+ throw new APIConnectionTimeoutError();
444
444
  }
445
- throw new APIConnectionError({ cause: response })
445
+ throw new APIConnectionError({ cause: response });
446
446
  }
447
447
 
448
- const responseHeaders = createResponseHeaders(response.headers)
448
+ const responseHeaders = createResponseHeaders(response.headers);
449
449
 
450
450
  if (!response.ok) {
451
451
  if (retriesRemaining && this.shouldRetry(response)) {
452
- const retryMessage = `retrying, ${retriesRemaining} attempts remaining`
453
- debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders)
454
- return this.retryRequest(options, retriesRemaining, responseHeaders)
452
+ const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
453
+ debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders);
454
+ return this.retryRequest(options, retriesRemaining, responseHeaders);
455
455
  }
456
456
 
457
- const errText = await response.text().catch((e: any) => castToError(e).message)
458
- const errJSON = safeJSON(errText)
459
- const errMessage = errJSON ? undefined : errText
460
- const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`
457
+ const errText = await response.text().catch((e: any) => castToError(e).message);
458
+ const errJSON = safeJSON(errText);
459
+ const errMessage = errJSON ? undefined : errText;
460
+ const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;
461
461
 
462
- debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage)
462
+ debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);
463
463
 
464
- const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders)
465
- throw err
464
+ const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);
465
+ throw err;
466
466
  }
467
467
 
468
- return { response, options, controller }
468
+ return { response, options, controller };
469
469
  }
470
470
 
471
471
  requestAPIList<Item = unknown, PageClass extends AbstractPage<Item> = AbstractPage<Item>>(
472
472
  Page: new (...args: ConstructorParameters<typeof AbstractPage>) => PageClass,
473
473
  options: FinalRequestOptions,
474
474
  ): PagePromise<PageClass, Item> {
475
- const request = this.makeRequest(options, null)
476
- return new PagePromise<PageClass, Item>(this, request, Page)
475
+ const request = this.makeRequest(options, null);
476
+ return new PagePromise<PageClass, Item>(this, request, Page);
477
477
  }
478
478
 
479
479
  buildURL<Req>(path: string, query: Req | null | undefined): string {
480
480
  const url =
481
481
  isAbsoluteURL(path) ?
482
482
  new URL(path)
483
- : new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path))
483
+ : new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
484
484
 
485
- const defaultQuery = this.defaultQuery()
485
+ const defaultQuery = this.defaultQuery();
486
486
  if (!isEmptyObj(defaultQuery)) {
487
- query = { ...defaultQuery, ...query } as Req
487
+ query = { ...defaultQuery, ...query } as Req;
488
488
  }
489
489
 
490
490
  if (typeof query === 'object' && query && !Array.isArray(query)) {
491
- url.search = this.stringifyQuery(query as Record<string, unknown>)
491
+ url.search = this.stringifyQuery(query as Record<string, unknown>);
492
492
  }
493
493
 
494
- return url.toString()
494
+ return url.toString();
495
495
  }
496
496
 
497
497
  protected stringifyQuery(query: Record<string, unknown>): string {
@@ -499,16 +499,16 @@ export abstract class APIClient {
499
499
  .filter(([_, value]) => typeof value !== 'undefined')
500
500
  .map(([key, value]) => {
501
501
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
502
- return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
502
+ return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
503
503
  }
504
504
  if (value === null) {
505
- return `${encodeURIComponent(key)}=`
505
+ return `${encodeURIComponent(key)}=`;
506
506
  }
507
507
  throw new LorikeetError(
508
508
  `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`,
509
- )
509
+ );
510
510
  })
511
- .join('&')
511
+ .join('&');
512
512
  }
513
513
 
514
514
  async fetchWithTimeout(
@@ -517,46 +517,46 @@ export abstract class APIClient {
517
517
  ms: number,
518
518
  controller: AbortController,
519
519
  ): Promise<Response> {
520
- const { signal, ...options } = init || {}
521
- if (signal) signal.addEventListener('abort', () => controller.abort())
520
+ const { signal, ...options } = init || {};
521
+ if (signal) signal.addEventListener('abort', () => controller.abort());
522
522
 
523
- const timeout = setTimeout(() => controller.abort(), ms)
523
+ const timeout = setTimeout(() => controller.abort(), ms);
524
524
 
525
525
  return (
526
526
  this.getRequestClient()
527
527
  // use undefined this binding; fetch errors if bound to something else in browser/cloudflare
528
528
  .fetch.call(undefined, url, { signal: controller.signal as any, ...options })
529
529
  .finally(() => {
530
- clearTimeout(timeout)
530
+ clearTimeout(timeout);
531
531
  })
532
- )
532
+ );
533
533
  }
534
534
 
535
535
  protected getRequestClient(): RequestClient {
536
- return { fetch: this.fetch }
536
+ return { fetch: this.fetch };
537
537
  }
538
538
 
539
539
  private shouldRetry(response: Response): boolean {
540
540
  // Note this is not a standard header.
541
- const shouldRetryHeader = response.headers.get('x-should-retry')
541
+ const shouldRetryHeader = response.headers.get('x-should-retry');
542
542
 
543
543
  // If the server explicitly says whether or not to retry, obey.
544
- if (shouldRetryHeader === 'true') return true
545
- if (shouldRetryHeader === 'false') return false
544
+ if (shouldRetryHeader === 'true') return true;
545
+ if (shouldRetryHeader === 'false') return false;
546
546
 
547
547
  // Retry on request timeouts.
548
- if (response.status === 408) return true
548
+ if (response.status === 408) return true;
549
549
 
550
550
  // Retry on lock timeouts.
551
- if (response.status === 409) return true
551
+ if (response.status === 409) return true;
552
552
 
553
553
  // Retry on rate limits.
554
- if (response.status === 429) return true
554
+ if (response.status === 429) return true;
555
555
 
556
556
  // Retry internal errors.
557
- if (response.status >= 500) return true
557
+ if (response.status >= 500) return true;
558
558
 
559
- return false
559
+ return false;
560
560
  }
561
561
 
562
562
  private async retryRequest(
@@ -564,124 +564,124 @@ export abstract class APIClient {
564
564
  retriesRemaining: number,
565
565
  responseHeaders?: Headers | undefined,
566
566
  ): Promise<APIResponseProps> {
567
- let timeoutMillis: number | undefined
567
+ let timeoutMillis: number | undefined;
568
568
 
569
569
  // Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it.
570
- const retryAfterMillisHeader = responseHeaders?.['retry-after-ms']
570
+ const retryAfterMillisHeader = responseHeaders?.['retry-after-ms'];
571
571
  if (retryAfterMillisHeader) {
572
- const timeoutMs = parseFloat(retryAfterMillisHeader)
572
+ const timeoutMs = parseFloat(retryAfterMillisHeader);
573
573
  if (!Number.isNaN(timeoutMs)) {
574
- timeoutMillis = timeoutMs
574
+ timeoutMillis = timeoutMs;
575
575
  }
576
576
  }
577
577
 
578
578
  // About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
579
- const retryAfterHeader = responseHeaders?.['retry-after']
579
+ const retryAfterHeader = responseHeaders?.['retry-after'];
580
580
  if (retryAfterHeader && !timeoutMillis) {
581
- const timeoutSeconds = parseFloat(retryAfterHeader)
581
+ const timeoutSeconds = parseFloat(retryAfterHeader);
582
582
  if (!Number.isNaN(timeoutSeconds)) {
583
- timeoutMillis = timeoutSeconds * 1000
583
+ timeoutMillis = timeoutSeconds * 1000;
584
584
  } else {
585
- timeoutMillis = Date.parse(retryAfterHeader) - Date.now()
585
+ timeoutMillis = Date.parse(retryAfterHeader) - Date.now();
586
586
  }
587
587
  }
588
588
 
589
589
  // If the API asks us to wait a certain amount of time (and it's a reasonable amount),
590
590
  // just do what it says, but otherwise calculate a default
591
591
  if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) {
592
- const maxRetries = options.maxRetries ?? this.maxRetries
593
- timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries)
592
+ const maxRetries = options.maxRetries ?? this.maxRetries;
593
+ timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
594
594
  }
595
- await sleep(timeoutMillis)
595
+ await sleep(timeoutMillis);
596
596
 
597
- return this.makeRequest(options, retriesRemaining - 1)
597
+ return this.makeRequest(options, retriesRemaining - 1);
598
598
  }
599
599
 
600
600
  private calculateDefaultRetryTimeoutMillis(retriesRemaining: number, maxRetries: number): number {
601
- const initialRetryDelay = 0.5
602
- const maxRetryDelay = 8.0
601
+ const initialRetryDelay = 0.5;
602
+ const maxRetryDelay = 8.0;
603
603
 
604
- const numRetries = maxRetries - retriesRemaining
604
+ const numRetries = maxRetries - retriesRemaining;
605
605
 
606
606
  // Apply exponential backoff, but not more than the max.
607
- const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay)
607
+ const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);
608
608
 
609
609
  // Apply some jitter, take up to at most 25 percent of the retry time.
610
- const jitter = 1 - Math.random() * 0.25
610
+ const jitter = 1 - Math.random() * 0.25;
611
611
 
612
- return sleepSeconds * jitter * 1000
612
+ return sleepSeconds * jitter * 1000;
613
613
  }
614
614
 
615
615
  private getUserAgent(): string {
616
- return `${this.constructor.name}/JS ${VERSION}`
616
+ return `${this.constructor.name}/JS ${VERSION}`;
617
617
  }
618
618
  }
619
619
 
620
- export type PageInfo = { url: URL } | { params: Record<string, unknown> | null }
620
+ export type PageInfo = { url: URL } | { params: Record<string, unknown> | null };
621
621
 
622
622
  export abstract class AbstractPage<Item> implements AsyncIterable<Item> {
623
- #client: APIClient
624
- protected options: FinalRequestOptions
623
+ #client: APIClient;
624
+ protected options: FinalRequestOptions;
625
625
 
626
- protected response: Response
627
- protected body: unknown
626
+ protected response: Response;
627
+ protected body: unknown;
628
628
 
629
629
  constructor(client: APIClient, response: Response, body: unknown, options: FinalRequestOptions) {
630
- this.#client = client
631
- this.options = options
632
- this.response = response
633
- this.body = body
630
+ this.#client = client;
631
+ this.options = options;
632
+ this.response = response;
633
+ this.body = body;
634
634
  }
635
635
 
636
636
  /**
637
637
  * @deprecated Use nextPageInfo instead
638
638
  */
639
- abstract nextPageParams(): Partial<Record<string, unknown>> | null
640
- abstract nextPageInfo(): PageInfo | null
639
+ abstract nextPageParams(): Partial<Record<string, unknown>> | null;
640
+ abstract nextPageInfo(): PageInfo | null;
641
641
 
642
- abstract getPaginatedItems(): Item[]
642
+ abstract getPaginatedItems(): Item[];
643
643
 
644
644
  hasNextPage(): boolean {
645
- const items = this.getPaginatedItems()
646
- if (!items.length) return false
647
- return this.nextPageInfo() != null
645
+ const items = this.getPaginatedItems();
646
+ if (!items.length) return false;
647
+ return this.nextPageInfo() != null;
648
648
  }
649
649
 
650
650
  async getNextPage(): Promise<this> {
651
- const nextInfo = this.nextPageInfo()
651
+ const nextInfo = this.nextPageInfo();
652
652
  if (!nextInfo) {
653
653
  throw new LorikeetError(
654
654
  'No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.',
655
- )
655
+ );
656
656
  }
657
- const nextOptions = { ...this.options }
657
+ const nextOptions = { ...this.options };
658
658
  if ('params' in nextInfo && typeof nextOptions.query === 'object') {
659
- nextOptions.query = { ...nextOptions.query, ...nextInfo.params }
659
+ nextOptions.query = { ...nextOptions.query, ...nextInfo.params };
660
660
  } else if ('url' in nextInfo) {
661
- const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()]
661
+ const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];
662
662
  for (const [key, value] of params) {
663
- nextInfo.url.searchParams.set(key, value as any)
663
+ nextInfo.url.searchParams.set(key, value as any);
664
664
  }
665
- nextOptions.query = undefined
666
- nextOptions.path = nextInfo.url.toString()
665
+ nextOptions.query = undefined;
666
+ nextOptions.path = nextInfo.url.toString();
667
667
  }
668
- return await this.#client.requestAPIList(this.constructor as any, nextOptions)
668
+ return await this.#client.requestAPIList(this.constructor as any, nextOptions);
669
669
  }
670
670
 
671
671
  async *iterPages(): AsyncGenerator<this> {
672
672
  // eslint-disable-next-line @typescript-eslint/no-this-alias
673
- let page: this = this
674
- yield page
673
+ let page: this = this;
674
+ yield page;
675
675
  while (page.hasNextPage()) {
676
- page = await page.getNextPage()
677
- yield page
676
+ page = await page.getNextPage();
677
+ yield page;
678
678
  }
679
679
  }
680
680
 
681
681
  async *[Symbol.asyncIterator](): AsyncGenerator<Item> {
682
682
  for await (const page of this.iterPages()) {
683
683
  for (const item of page.getPaginatedItems()) {
684
- yield item
684
+ yield item;
685
685
  }
686
686
  }
687
687
  }
@@ -711,7 +711,7 @@ export class PagePromise<
711
711
  super(
712
712
  request,
713
713
  async (props) => new Page(client, props.response, await defaultParseResponse(props), props.options),
714
- )
714
+ );
715
715
  }
716
716
 
717
717
  /**
@@ -722,9 +722,9 @@ export class PagePromise<
722
722
  * }
723
723
  */
724
724
  async *[Symbol.asyncIterator](): AsyncGenerator<Item> {
725
- const page = await this
725
+ const page = await this;
726
726
  for await (const item of page) {
727
- yield item
727
+ yield item;
728
728
  }
729
729
  }
730
730
  }
@@ -739,39 +739,39 @@ export const createResponseHeaders = (
739
739
  ),
740
740
  {
741
741
  get(target, name) {
742
- const key = name.toString()
743
- return target[key.toLowerCase()] || target[key]
742
+ const key = name.toString();
743
+ return target[key.toLowerCase()] || target[key];
744
744
  },
745
745
  },
746
- )
747
- }
746
+ );
747
+ };
748
748
 
749
- type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'
749
+ type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete';
750
750
 
751
- export type RequestClient = { fetch: Fetch }
752
- export type Headers = Record<string, string | null | undefined>
753
- export type DefaultQuery = Record<string, string | undefined>
754
- export type KeysEnum<T> = { [P in keyof Required<T>]: true }
751
+ export type RequestClient = { fetch: Fetch };
752
+ export type Headers = Record<string, string | null | undefined>;
753
+ export type DefaultQuery = Record<string, string | undefined>;
754
+ export type KeysEnum<T> = { [P in keyof Required<T>]: true };
755
755
 
756
756
  export type RequestOptions<
757
757
  Req = unknown | Record<string, unknown> | Readable | BlobLike | ArrayBufferView | ArrayBuffer,
758
758
  > = {
759
- method?: HTTPMethod
760
- path?: string
761
- query?: Req | undefined
762
- body?: Req | null | undefined
763
- headers?: Headers | undefined
764
-
765
- maxRetries?: number
766
- stream?: boolean | undefined
767
- timeout?: number
768
- httpAgent?: Agent
769
- signal?: AbortSignal | undefined | null
770
- idempotencyKey?: string
771
-
772
- __binaryRequest?: boolean | undefined
773
- __binaryResponse?: boolean | undefined
774
- }
759
+ method?: HTTPMethod;
760
+ path?: string;
761
+ query?: Req | undefined;
762
+ body?: Req | null | undefined;
763
+ headers?: Headers | undefined;
764
+
765
+ maxRetries?: number;
766
+ stream?: boolean | undefined;
767
+ timeout?: number;
768
+ httpAgent?: Agent;
769
+ signal?: AbortSignal | undefined | null;
770
+ idempotencyKey?: string;
771
+
772
+ __binaryRequest?: boolean | undefined;
773
+ __binaryResponse?: boolean | undefined;
774
+ };
775
775
 
776
776
  // This is required so that we can determine if a given object matches the RequestOptions
777
777
  // type at runtime. While this requires duplication, it is enforced by the TypeScript
@@ -792,7 +792,7 @@ const requestOptionsKeys: KeysEnum<RequestOptions> = {
792
792
 
793
793
  __binaryRequest: true,
794
794
  __binaryResponse: true,
795
- }
795
+ };
796
796
 
797
797
  export const isRequestOptions = (obj: unknown): obj is RequestOptions => {
798
798
  return (
@@ -800,18 +800,18 @@ export const isRequestOptions = (obj: unknown): obj is RequestOptions => {
800
800
  obj !== null &&
801
801
  !isEmptyObj(obj) &&
802
802
  Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k))
803
- )
804
- }
803
+ );
804
+ };
805
805
 
806
806
  export type FinalRequestOptions<Req = unknown | Record<string, unknown> | Readable | DataView> =
807
807
  RequestOptions<Req> & {
808
- method: HTTPMethod
809
- path: string
810
- }
808
+ method: HTTPMethod;
809
+ path: string;
810
+ };
811
811
 
812
- declare const Deno: any
813
- declare const EdgeRuntime: any
814
- type Arch = 'x32' | 'x64' | 'arm' | 'arm64' | `other:${string}` | 'unknown'
812
+ declare const Deno: any;
813
+ declare const EdgeRuntime: any;
814
+ type Arch = 'x32' | 'x64' | 'arm' | 'arm64' | `other:${string}` | 'unknown';
815
815
  type PlatformName =
816
816
  | 'MacOS'
817
817
  | 'Linux'
@@ -821,16 +821,16 @@ type PlatformName =
821
821
  | 'iOS'
822
822
  | 'Android'
823
823
  | `Other:${string}`
824
- | 'Unknown'
825
- type Browser = 'ie' | 'edge' | 'chrome' | 'firefox' | 'safari'
824
+ | 'Unknown';
825
+ type Browser = 'ie' | 'edge' | 'chrome' | 'firefox' | 'safari';
826
826
  type PlatformProperties = {
827
- 'X-Stainless-Lang': 'js'
828
- 'X-Stainless-Package-Version': string
829
- 'X-Stainless-OS': PlatformName
830
- 'X-Stainless-Arch': Arch
831
- 'X-Stainless-Runtime': 'node' | 'deno' | 'edge' | `browser:${Browser}` | 'unknown'
832
- 'X-Stainless-Runtime-Version': string
833
- }
827
+ 'X-Stainless-Lang': 'js';
828
+ 'X-Stainless-Package-Version': string;
829
+ 'X-Stainless-OS': PlatformName;
830
+ 'X-Stainless-Arch': Arch;
831
+ 'X-Stainless-Runtime': 'node' | 'deno' | 'edge' | `browser:${Browser}` | 'unknown';
832
+ 'X-Stainless-Runtime-Version': string;
833
+ };
834
834
  const getPlatformProperties = (): PlatformProperties => {
835
835
  if (typeof Deno !== 'undefined' && Deno.build != null) {
836
836
  return {
@@ -841,7 +841,7 @@ const getPlatformProperties = (): PlatformProperties => {
841
841
  'X-Stainless-Runtime': 'deno',
842
842
  'X-Stainless-Runtime-Version':
843
843
  typeof Deno.version === 'string' ? Deno.version : (Deno.version?.deno ?? 'unknown'),
844
- }
844
+ };
845
845
  }
846
846
  if (typeof EdgeRuntime !== 'undefined') {
847
847
  return {
@@ -851,7 +851,7 @@ const getPlatformProperties = (): PlatformProperties => {
851
851
  'X-Stainless-Arch': `other:${EdgeRuntime}`,
852
852
  'X-Stainless-Runtime': 'edge',
853
853
  'X-Stainless-Runtime-Version': process.version,
854
- }
854
+ };
855
855
  }
856
856
  // Check if Node.js
857
857
  if (Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]') {
@@ -862,10 +862,10 @@ const getPlatformProperties = (): PlatformProperties => {
862
862
  'X-Stainless-Arch': normalizeArch(process.arch),
863
863
  'X-Stainless-Runtime': 'node',
864
864
  'X-Stainless-Runtime-Version': process.version,
865
- }
865
+ };
866
866
  }
867
867
 
868
- const browserInfo = getBrowserInfo()
868
+ const browserInfo = getBrowserInfo();
869
869
  if (browserInfo) {
870
870
  return {
871
871
  'X-Stainless-Lang': 'js',
@@ -874,7 +874,7 @@ const getPlatformProperties = (): PlatformProperties => {
874
874
  'X-Stainless-Arch': 'unknown',
875
875
  'X-Stainless-Runtime': `browser:${browserInfo.browser}`,
876
876
  'X-Stainless-Runtime-Version': browserInfo.version,
877
- }
877
+ };
878
878
  }
879
879
 
880
880
  // TODO add support for Cloudflare workers, etc.
@@ -885,20 +885,20 @@ const getPlatformProperties = (): PlatformProperties => {
885
885
  'X-Stainless-Arch': 'unknown',
886
886
  'X-Stainless-Runtime': 'unknown',
887
887
  'X-Stainless-Runtime-Version': 'unknown',
888
- }
889
- }
888
+ };
889
+ };
890
890
 
891
891
  type BrowserInfo = {
892
- browser: Browser
893
- version: string
894
- }
892
+ browser: Browser;
893
+ version: string;
894
+ };
895
895
 
896
- declare const navigator: { userAgent: string } | undefined
896
+ declare const navigator: { userAgent: string } | undefined;
897
897
 
898
898
  // Note: modified from https://github.com/JS-DevTools/host-environment/blob/b1ab79ecde37db5d6e163c050e54fe7d287d7c92/src/isomorphic.browser.ts
899
899
  function getBrowserInfo(): BrowserInfo | null {
900
900
  if (typeof navigator === 'undefined' || !navigator) {
901
- return null
901
+ return null;
902
902
  }
903
903
 
904
904
  // NOTE: The order matters here!
@@ -909,21 +909,21 @@ function getBrowserInfo(): BrowserInfo | null {
909
909
  { key: 'chrome' as const, pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
910
910
  { key: 'firefox' as const, pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
911
911
  { key: 'safari' as const, pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ },
912
- ]
912
+ ];
913
913
 
914
914
  // Find the FIRST matching browser
915
915
  for (const { key, pattern } of browserPatterns) {
916
- const match = pattern.exec(navigator.userAgent)
916
+ const match = pattern.exec(navigator.userAgent);
917
917
  if (match) {
918
- const major = match[1] || 0
919
- const minor = match[2] || 0
920
- const patch = match[3] || 0
918
+ const major = match[1] || 0;
919
+ const minor = match[2] || 0;
920
+ const patch = match[3] || 0;
921
921
 
922
- return { browser: key, version: `${major}.${minor}.${patch}` }
922
+ return { browser: key, version: `${major}.${minor}.${patch}` };
923
923
  }
924
924
  }
925
925
 
926
- return null
926
+ return null;
927
927
  }
928
928
 
929
929
  const normalizeArch = (arch: string): Arch => {
@@ -931,13 +931,13 @@ const normalizeArch = (arch: string): Arch => {
931
931
  // - https://nodejs.org/api/process.html#processarch
932
932
  // Deno docs:
933
933
  // - https://doc.deno.land/deno/stable/~/Deno.build
934
- if (arch === 'x32') return 'x32'
935
- if (arch === 'x86_64' || arch === 'x64') return 'x64'
936
- if (arch === 'arm') return 'arm'
937
- if (arch === 'aarch64' || arch === 'arm64') return 'arm64'
938
- if (arch) return `other:${arch}`
939
- return 'unknown'
940
- }
934
+ if (arch === 'x32') return 'x32';
935
+ if (arch === 'x86_64' || arch === 'x64') return 'x64';
936
+ if (arch === 'arm') return 'arm';
937
+ if (arch === 'aarch64' || arch === 'arm64') return 'arm64';
938
+ if (arch) return `other:${arch}`;
939
+ return 'unknown';
940
+ };
941
941
 
942
942
  const normalizePlatform = (platform: string): PlatformName => {
943
943
  // Node platforms:
@@ -946,68 +946,68 @@ const normalizePlatform = (platform: string): PlatformName => {
946
946
  // - https://doc.deno.land/deno/stable/~/Deno.build
947
947
  // - https://github.com/denoland/deno/issues/14799
948
948
 
949
- platform = platform.toLowerCase()
949
+ platform = platform.toLowerCase();
950
950
 
951
951
  // NOTE: this iOS check is untested and may not work
952
952
  // Node does not work natively on IOS, there is a fork at
953
953
  // https://github.com/nodejs-mobile/nodejs-mobile
954
954
  // however it is unknown at the time of writing how to detect if it is running
955
- if (platform.includes('ios')) return 'iOS'
956
- if (platform === 'android') return 'Android'
957
- if (platform === 'darwin') return 'MacOS'
958
- if (platform === 'win32') return 'Windows'
959
- if (platform === 'freebsd') return 'FreeBSD'
960
- if (platform === 'openbsd') return 'OpenBSD'
961
- if (platform === 'linux') return 'Linux'
962
- if (platform) return `Other:${platform}`
963
- return 'Unknown'
964
- }
965
-
966
- let _platformHeaders: PlatformProperties
955
+ if (platform.includes('ios')) return 'iOS';
956
+ if (platform === 'android') return 'Android';
957
+ if (platform === 'darwin') return 'MacOS';
958
+ if (platform === 'win32') return 'Windows';
959
+ if (platform === 'freebsd') return 'FreeBSD';
960
+ if (platform === 'openbsd') return 'OpenBSD';
961
+ if (platform === 'linux') return 'Linux';
962
+ if (platform) return `Other:${platform}`;
963
+ return 'Unknown';
964
+ };
965
+
966
+ let _platformHeaders: PlatformProperties;
967
967
  const getPlatformHeaders = () => {
968
- return (_platformHeaders ??= getPlatformProperties())
969
- }
968
+ return (_platformHeaders ??= getPlatformProperties());
969
+ };
970
970
 
971
971
  export const safeJSON = (text: string) => {
972
972
  try {
973
- return JSON.parse(text)
973
+ return JSON.parse(text);
974
974
  } catch (err) {
975
- return undefined
975
+ return undefined;
976
976
  }
977
- }
977
+ };
978
978
 
979
979
  // https://stackoverflow.com/a/19709846
980
- const startsWithSchemeRegexp = new RegExp('^(?:[a-z]+:)?//', 'i')
980
+ const startsWithSchemeRegexp = new RegExp('^(?:[a-z]+:)?//', 'i');
981
981
  const isAbsoluteURL = (url: string): boolean => {
982
- return startsWithSchemeRegexp.test(url)
983
- }
982
+ return startsWithSchemeRegexp.test(url);
983
+ };
984
984
 
985
- export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
985
+ export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
986
986
 
987
987
  const validatePositiveInteger = (name: string, n: unknown): number => {
988
988
  if (typeof n !== 'number' || !Number.isInteger(n)) {
989
- throw new LorikeetError(`${name} must be an integer`)
989
+ throw new LorikeetError(`${name} must be an integer`);
990
990
  }
991
991
  if (n < 0) {
992
- throw new LorikeetError(`${name} must be a positive integer`)
992
+ throw new LorikeetError(`${name} must be a positive integer`);
993
993
  }
994
- return n
995
- }
994
+ return n;
995
+ };
996
996
 
997
997
  export const castToError = (err: any): Error => {
998
- if (err instanceof Error) return err
998
+ if (err instanceof Error) return err;
999
999
  if (typeof err === 'object' && err !== null) {
1000
1000
  try {
1001
- return new Error(JSON.stringify(err))
1001
+ return new Error(JSON.stringify(err));
1002
1002
  } catch {}
1003
1003
  }
1004
- return new Error(err)
1005
- }
1004
+ return new Error(err);
1005
+ };
1006
1006
 
1007
1007
  export const ensurePresent = <T>(value: T | null | undefined): T => {
1008
- if (value == null) throw new LorikeetError(`Expected a value to be given but received ${value} instead.`)
1009
- return value
1010
- }
1008
+ if (value == null) throw new LorikeetError(`Expected a value to be given but received ${value} instead.`);
1009
+ return value;
1010
+ };
1011
1011
 
1012
1012
  /**
1013
1013
  * Read an environment variable.
@@ -1018,65 +1018,65 @@ export const ensurePresent = <T>(value: T | null | undefined): T => {
1018
1018
  */
1019
1019
  export const readEnv = (env: string): string | undefined => {
1020
1020
  if (typeof process !== 'undefined') {
1021
- return process.env?.[env]?.trim() ?? undefined
1021
+ return process.env?.[env]?.trim() ?? undefined;
1022
1022
  }
1023
1023
  if (typeof Deno !== 'undefined') {
1024
- return Deno.env?.get?.(env)?.trim()
1024
+ return Deno.env?.get?.(env)?.trim();
1025
1025
  }
1026
- return undefined
1027
- }
1026
+ return undefined;
1027
+ };
1028
1028
 
1029
1029
  export const coerceInteger = (value: unknown): number => {
1030
- if (typeof value === 'number') return Math.round(value)
1031
- if (typeof value === 'string') return parseInt(value, 10)
1030
+ if (typeof value === 'number') return Math.round(value);
1031
+ if (typeof value === 'string') return parseInt(value, 10);
1032
1032
 
1033
- throw new LorikeetError(`Could not coerce ${value} (type: ${typeof value}) into a number`)
1034
- }
1033
+ throw new LorikeetError(`Could not coerce ${value} (type: ${typeof value}) into a number`);
1034
+ };
1035
1035
 
1036
1036
  export const coerceFloat = (value: unknown): number => {
1037
- if (typeof value === 'number') return value
1038
- if (typeof value === 'string') return parseFloat(value)
1037
+ if (typeof value === 'number') return value;
1038
+ if (typeof value === 'string') return parseFloat(value);
1039
1039
 
1040
- throw new LorikeetError(`Could not coerce ${value} (type: ${typeof value}) into a number`)
1041
- }
1040
+ throw new LorikeetError(`Could not coerce ${value} (type: ${typeof value}) into a number`);
1041
+ };
1042
1042
 
1043
1043
  export const coerceBoolean = (value: unknown): boolean => {
1044
- if (typeof value === 'boolean') return value
1045
- if (typeof value === 'string') return value === 'true'
1046
- return Boolean(value)
1047
- }
1044
+ if (typeof value === 'boolean') return value;
1045
+ if (typeof value === 'string') return value === 'true';
1046
+ return Boolean(value);
1047
+ };
1048
1048
 
1049
1049
  export const maybeCoerceInteger = (value: unknown): number | undefined => {
1050
1050
  if (value === undefined) {
1051
- return undefined
1051
+ return undefined;
1052
1052
  }
1053
- return coerceInteger(value)
1054
- }
1053
+ return coerceInteger(value);
1054
+ };
1055
1055
 
1056
1056
  export const maybeCoerceFloat = (value: unknown): number | undefined => {
1057
1057
  if (value === undefined) {
1058
- return undefined
1058
+ return undefined;
1059
1059
  }
1060
- return coerceFloat(value)
1061
- }
1060
+ return coerceFloat(value);
1061
+ };
1062
1062
 
1063
1063
  export const maybeCoerceBoolean = (value: unknown): boolean | undefined => {
1064
1064
  if (value === undefined) {
1065
- return undefined
1065
+ return undefined;
1066
1066
  }
1067
- return coerceBoolean(value)
1068
- }
1067
+ return coerceBoolean(value);
1068
+ };
1069
1069
 
1070
1070
  // https://stackoverflow.com/a/34491287
1071
1071
  export function isEmptyObj(obj: Object | null | undefined): boolean {
1072
- if (!obj) return true
1073
- for (const _k in obj) return false
1074
- return true
1072
+ if (!obj) return true;
1073
+ for (const _k in obj) return false;
1074
+ return true;
1075
1075
  }
1076
1076
 
1077
1077
  // https://eslint.org/docs/latest/rules/no-prototype-builtins
1078
1078
  export function hasOwn(obj: Object, key: string): boolean {
1079
- return Object.prototype.hasOwnProperty.call(obj, key)
1079
+ return Object.prototype.hasOwnProperty.call(obj, key);
1080
1080
  }
1081
1081
 
1082
1082
  /**
@@ -1087,23 +1087,23 @@ export function hasOwn(obj: Object, key: string): boolean {
1087
1087
  */
1088
1088
  function applyHeadersMut(targetHeaders: Headers, newHeaders: Headers): void {
1089
1089
  for (const k in newHeaders) {
1090
- if (!hasOwn(newHeaders, k)) continue
1091
- const lowerKey = k.toLowerCase()
1092
- if (!lowerKey) continue
1090
+ if (!hasOwn(newHeaders, k)) continue;
1091
+ const lowerKey = k.toLowerCase();
1092
+ if (!lowerKey) continue;
1093
1093
 
1094
- const val = newHeaders[k]
1094
+ const val = newHeaders[k];
1095
1095
 
1096
1096
  if (val === null) {
1097
- delete targetHeaders[lowerKey]
1097
+ delete targetHeaders[lowerKey];
1098
1098
  } else if (val !== undefined) {
1099
- targetHeaders[lowerKey] = val
1099
+ targetHeaders[lowerKey] = val;
1100
1100
  }
1101
1101
  }
1102
1102
  }
1103
1103
 
1104
1104
  export function debug(action: string, ...args: any[]) {
1105
1105
  if (typeof process !== 'undefined' && process?.env?.['DEBUG'] === 'true') {
1106
- console.log(`Lorikeet:DEBUG:${action}`, ...args)
1106
+ console.log(`Lorikeet:DEBUG:${action}`, ...args);
1107
1107
  }
1108
1108
  }
1109
1109
 
@@ -1112,11 +1112,11 @@ export function debug(action: string, ...args: any[]) {
1112
1112
  */
1113
1113
  const uuid4 = () => {
1114
1114
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
1115
- const r = (Math.random() * 16) | 0
1116
- const v = c === 'x' ? r : (r & 0x3) | 0x8
1117
- return v.toString(16)
1118
- })
1119
- }
1115
+ const r = (Math.random() * 16) | 0;
1116
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
1117
+ return v.toString(16);
1118
+ });
1119
+ };
1120
1120
 
1121
1121
  export const isRunningInBrowser = () => {
1122
1122
  return (
@@ -1126,37 +1126,37 @@ export const isRunningInBrowser = () => {
1126
1126
  typeof window.document !== 'undefined' &&
1127
1127
  // @ts-ignore
1128
1128
  typeof navigator !== 'undefined'
1129
- )
1130
- }
1129
+ );
1130
+ };
1131
1131
 
1132
1132
  export interface HeadersProtocol {
1133
- get: (header: string) => string | null | undefined
1133
+ get: (header: string) => string | null | undefined;
1134
1134
  }
1135
- export type HeadersLike = Record<string, string | string[] | undefined> | HeadersProtocol
1135
+ export type HeadersLike = Record<string, string | string[] | undefined> | HeadersProtocol;
1136
1136
 
1137
1137
  export const isHeadersProtocol = (headers: any): headers is HeadersProtocol => {
1138
- return typeof headers?.get === 'function'
1139
- }
1138
+ return typeof headers?.get === 'function';
1139
+ };
1140
1140
 
1141
1141
  export const getRequiredHeader = (headers: HeadersLike | Headers, header: string): string => {
1142
- const foundHeader = getHeader(headers, header)
1142
+ const foundHeader = getHeader(headers, header);
1143
1143
  if (foundHeader === undefined) {
1144
- throw new Error(`Could not find ${header} header`)
1144
+ throw new Error(`Could not find ${header} header`);
1145
1145
  }
1146
- return foundHeader
1147
- }
1146
+ return foundHeader;
1147
+ };
1148
1148
 
1149
1149
  export const getHeader = (headers: HeadersLike | Headers, header: string): string | undefined => {
1150
- const lowerCasedHeader = header.toLowerCase()
1150
+ const lowerCasedHeader = header.toLowerCase();
1151
1151
  if (isHeadersProtocol(headers)) {
1152
1152
  // to deal with the case where the header looks like Stainless-Event-Id
1153
1153
  const intercapsHeader =
1154
1154
  header[0]?.toUpperCase() +
1155
- header.substring(1).replace(/([^\w])(\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase())
1155
+ header.substring(1).replace(/([^\w])(\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());
1156
1156
  for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {
1157
- const value = headers.get(key)
1157
+ const value = headers.get(key);
1158
1158
  if (value) {
1159
- return value
1159
+ return value;
1160
1160
  }
1161
1161
  }
1162
1162
  }
@@ -1164,33 +1164,33 @@ export const getHeader = (headers: HeadersLike | Headers, header: string): strin
1164
1164
  for (const [key, value] of Object.entries(headers)) {
1165
1165
  if (key.toLowerCase() === lowerCasedHeader) {
1166
1166
  if (Array.isArray(value)) {
1167
- if (value.length <= 1) return value[0]
1168
- console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`)
1169
- return value[0]
1167
+ if (value.length <= 1) return value[0];
1168
+ console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);
1169
+ return value[0];
1170
1170
  }
1171
- return value
1171
+ return value;
1172
1172
  }
1173
1173
  }
1174
1174
 
1175
- return undefined
1176
- }
1175
+ return undefined;
1176
+ };
1177
1177
 
1178
1178
  /**
1179
1179
  * Encodes a string to Base64 format.
1180
1180
  */
1181
1181
  export const toBase64 = (str: string | null | undefined): string => {
1182
- if (!str) return ''
1182
+ if (!str) return '';
1183
1183
  if (typeof Buffer !== 'undefined') {
1184
- return Buffer.from(str).toString('base64')
1184
+ return Buffer.from(str).toString('base64');
1185
1185
  }
1186
1186
 
1187
1187
  if (typeof btoa !== 'undefined') {
1188
- return btoa(str)
1188
+ return btoa(str);
1189
1189
  }
1190
1190
 
1191
- throw new LorikeetError('Cannot generate b64 string; Expected `Buffer` or `btoa` to be defined')
1192
- }
1191
+ throw new LorikeetError('Cannot generate b64 string; Expected `Buffer` or `btoa` to be defined');
1192
+ };
1193
1193
 
1194
1194
  export function isObj(obj: unknown): obj is Record<string, unknown> {
1195
- return obj != null && typeof obj === 'object' && !Array.isArray(obj)
1195
+ return obj != null && typeof obj === 'object' && !Array.isArray(obj);
1196
1196
  }