@roarkanalytics/sdk 0.1.0-alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (246) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/LICENSE +201 -0
  3. package/README.md +344 -0
  4. package/api-promise.d.mts +47 -0
  5. package/api-promise.d.mts.map +1 -0
  6. package/api-promise.d.ts +47 -0
  7. package/api-promise.d.ts.map +1 -0
  8. package/api-promise.js +84 -0
  9. package/api-promise.js.map +1 -0
  10. package/api-promise.mjs +80 -0
  11. package/api-promise.mjs.map +1 -0
  12. package/client.d.mts +186 -0
  13. package/client.d.mts.map +1 -0
  14. package/client.d.ts +186 -0
  15. package/client.d.ts.map +1 -0
  16. package/client.js +449 -0
  17. package/client.js.map +1 -0
  18. package/client.mjs +422 -0
  19. package/client.mjs.map +1 -0
  20. package/error.d.mts +47 -0
  21. package/error.d.mts.map +1 -0
  22. package/error.d.ts +47 -0
  23. package/error.d.ts.map +1 -0
  24. package/error.js +113 -0
  25. package/error.js.map +1 -0
  26. package/error.mjs +97 -0
  27. package/error.mjs.map +1 -0
  28. package/index.d.mts +6 -0
  29. package/index.d.mts.map +1 -0
  30. package/index.d.ts +6 -0
  31. package/index.d.ts.map +1 -0
  32. package/index.js +30 -0
  33. package/index.js.map +1 -0
  34. package/index.mjs +7 -0
  35. package/index.mjs.map +1 -0
  36. package/internal/builtin-types.d.mts +65 -0
  37. package/internal/builtin-types.d.mts.map +1 -0
  38. package/internal/builtin-types.d.ts +65 -0
  39. package/internal/builtin-types.d.ts.map +1 -0
  40. package/internal/builtin-types.js +4 -0
  41. package/internal/builtin-types.js.map +1 -0
  42. package/internal/builtin-types.mjs +3 -0
  43. package/internal/builtin-types.mjs.map +1 -0
  44. package/internal/detect-platform.d.mts +15 -0
  45. package/internal/detect-platform.d.mts.map +1 -0
  46. package/internal/detect-platform.d.ts +15 -0
  47. package/internal/detect-platform.d.ts.map +1 -0
  48. package/internal/detect-platform.js +162 -0
  49. package/internal/detect-platform.js.map +1 -0
  50. package/internal/detect-platform.mjs +157 -0
  51. package/internal/detect-platform.mjs.map +1 -0
  52. package/internal/errors.d.mts +3 -0
  53. package/internal/errors.d.mts.map +1 -0
  54. package/internal/errors.d.ts +3 -0
  55. package/internal/errors.d.ts.map +1 -0
  56. package/internal/errors.js +26 -0
  57. package/internal/errors.js.map +1 -0
  58. package/internal/errors.mjs +21 -0
  59. package/internal/errors.mjs.map +1 -0
  60. package/internal/headers.d.mts +21 -0
  61. package/internal/headers.d.mts.map +1 -0
  62. package/internal/headers.d.ts +21 -0
  63. package/internal/headers.d.ts.map +1 -0
  64. package/internal/headers.js +77 -0
  65. package/internal/headers.js.map +1 -0
  66. package/internal/headers.mjs +72 -0
  67. package/internal/headers.mjs.map +1 -0
  68. package/internal/parse.d.mts +10 -0
  69. package/internal/parse.d.mts.map +1 -0
  70. package/internal/parse.d.ts +10 -0
  71. package/internal/parse.d.ts.map +1 -0
  72. package/internal/parse.js +28 -0
  73. package/internal/parse.js.map +1 -0
  74. package/internal/parse.mjs +24 -0
  75. package/internal/parse.mjs.map +1 -0
  76. package/internal/polyfill/crypto.node.d.ts +10 -0
  77. package/internal/polyfill/crypto.node.js +11 -0
  78. package/internal/polyfill/crypto.node.mjs +2 -0
  79. package/internal/polyfill/file.node.d.ts +9 -0
  80. package/internal/polyfill/file.node.js +17 -0
  81. package/internal/polyfill/file.node.mjs +9 -0
  82. package/internal/request-options.d.mts +34 -0
  83. package/internal/request-options.d.mts.map +1 -0
  84. package/internal/request-options.d.ts +34 -0
  85. package/internal/request-options.d.ts.map +1 -0
  86. package/internal/request-options.js +39 -0
  87. package/internal/request-options.js.map +1 -0
  88. package/internal/request-options.mjs +34 -0
  89. package/internal/request-options.mjs.map +1 -0
  90. package/internal/shim-types.d.mts +28 -0
  91. package/internal/shim-types.d.ts +28 -0
  92. package/internal/shims.d.mts +61 -0
  93. package/internal/shims.d.mts.map +1 -0
  94. package/internal/shims.d.ts +61 -0
  95. package/internal/shims.d.ts.map +1 -0
  96. package/internal/shims.js +101 -0
  97. package/internal/shims.js.map +1 -0
  98. package/internal/shims.mjs +92 -0
  99. package/internal/shims.mjs.map +1 -0
  100. package/internal/types.d.mts +68 -0
  101. package/internal/types.d.mts.map +1 -0
  102. package/internal/types.d.ts +68 -0
  103. package/internal/types.d.ts.map +1 -0
  104. package/internal/types.js +4 -0
  105. package/internal/types.js.map +1 -0
  106. package/internal/types.mjs +3 -0
  107. package/internal/types.mjs.map +1 -0
  108. package/internal/uploads.d.mts +73 -0
  109. package/internal/uploads.d.mts.map +1 -0
  110. package/internal/uploads.d.ts +73 -0
  111. package/internal/uploads.d.ts.map +1 -0
  112. package/internal/uploads.js +208 -0
  113. package/internal/uploads.js.map +1 -0
  114. package/internal/uploads.mjs +200 -0
  115. package/internal/uploads.mjs.map +1 -0
  116. package/internal/utils/base64.d.mts +3 -0
  117. package/internal/utils/base64.d.mts.map +1 -0
  118. package/internal/utils/base64.d.ts +3 -0
  119. package/internal/utils/base64.d.ts.map +1 -0
  120. package/internal/utils/base64.js +33 -0
  121. package/internal/utils/base64.js.map +1 -0
  122. package/internal/utils/base64.mjs +28 -0
  123. package/internal/utils/base64.mjs.map +1 -0
  124. package/internal/utils/env.d.mts +9 -0
  125. package/internal/utils/env.d.mts.map +1 -0
  126. package/internal/utils/env.d.ts +9 -0
  127. package/internal/utils/env.d.ts.map +1 -0
  128. package/internal/utils/env.js +22 -0
  129. package/internal/utils/env.js.map +1 -0
  130. package/internal/utils/env.mjs +18 -0
  131. package/internal/utils/env.mjs.map +1 -0
  132. package/internal/utils/log.d.mts +4 -0
  133. package/internal/utils/log.d.mts.map +1 -0
  134. package/internal/utils/log.d.ts +4 -0
  135. package/internal/utils/log.d.ts.map +1 -0
  136. package/internal/utils/log.js +47 -0
  137. package/internal/utils/log.js.map +1 -0
  138. package/internal/utils/log.mjs +43 -0
  139. package/internal/utils/log.mjs.map +1 -0
  140. package/internal/utils/sleep.d.mts +2 -0
  141. package/internal/utils/sleep.d.mts.map +1 -0
  142. package/internal/utils/sleep.d.ts +2 -0
  143. package/internal/utils/sleep.d.ts.map +1 -0
  144. package/internal/utils/sleep.js +7 -0
  145. package/internal/utils/sleep.js.map +1 -0
  146. package/internal/utils/sleep.mjs +3 -0
  147. package/internal/utils/sleep.mjs.map +1 -0
  148. package/internal/utils/uuid.d.mts +5 -0
  149. package/internal/utils/uuid.d.mts.map +1 -0
  150. package/internal/utils/uuid.d.ts +5 -0
  151. package/internal/utils/uuid.d.ts.map +1 -0
  152. package/internal/utils/uuid.js +15 -0
  153. package/internal/utils/uuid.js.map +1 -0
  154. package/internal/utils/uuid.mjs +11 -0
  155. package/internal/utils/uuid.mjs.map +1 -0
  156. package/internal/utils/values.d.mts +15 -0
  157. package/internal/utils/values.d.mts.map +1 -0
  158. package/internal/utils/values.d.ts +15 -0
  159. package/internal/utils/values.d.ts.map +1 -0
  160. package/internal/utils/values.js +100 -0
  161. package/internal/utils/values.js.map +1 -0
  162. package/internal/utils/values.mjs +84 -0
  163. package/internal/utils/values.mjs.map +1 -0
  164. package/internal/utils.d.mts +7 -0
  165. package/internal/utils.d.mts.map +1 -0
  166. package/internal/utils.d.ts +7 -0
  167. package/internal/utils.d.ts.map +1 -0
  168. package/internal/utils.js +24 -0
  169. package/internal/utils.js.map +1 -0
  170. package/internal/utils.mjs +8 -0
  171. package/internal/utils.mjs.map +1 -0
  172. package/package.json +119 -0
  173. package/resource.d.mts +6 -0
  174. package/resource.d.mts.map +1 -0
  175. package/resource.d.ts +6 -0
  176. package/resource.d.ts.map +1 -0
  177. package/resource.js +11 -0
  178. package/resource.js.map +1 -0
  179. package/resource.mjs +7 -0
  180. package/resource.mjs.map +1 -0
  181. package/resources/calls.d.mts +85 -0
  182. package/resources/calls.d.mts.map +1 -0
  183. package/resources/calls.d.ts +85 -0
  184. package/resources/calls.d.ts.map +1 -0
  185. package/resources/calls.js +15 -0
  186. package/resources/calls.js.map +1 -0
  187. package/resources/calls.mjs +11 -0
  188. package/resources/calls.mjs.map +1 -0
  189. package/resources/index.d.mts +2 -0
  190. package/resources/index.d.mts.map +1 -0
  191. package/resources/index.d.ts +2 -0
  192. package/resources/index.d.ts.map +1 -0
  193. package/resources/index.js +7 -0
  194. package/resources/index.js.map +1 -0
  195. package/resources/index.mjs +3 -0
  196. package/resources/index.mjs.map +1 -0
  197. package/src/api-promise.ts +92 -0
  198. package/src/client.ts +646 -0
  199. package/src/error.ts +130 -0
  200. package/src/index.ts +22 -0
  201. package/src/internal/builtin-types.ts +79 -0
  202. package/src/internal/detect-platform.ts +196 -0
  203. package/src/internal/errors.ts +22 -0
  204. package/src/internal/headers.ts +96 -0
  205. package/src/internal/parse.ts +41 -0
  206. package/src/internal/polyfill/crypto.node.d.ts +10 -0
  207. package/src/internal/polyfill/crypto.node.js +11 -0
  208. package/src/internal/polyfill/crypto.node.mjs +2 -0
  209. package/src/internal/polyfill/file.node.d.ts +9 -0
  210. package/src/internal/polyfill/file.node.js +17 -0
  211. package/src/internal/polyfill/file.node.mjs +9 -0
  212. package/src/internal/request-options.ts +67 -0
  213. package/src/internal/shim-types.d.ts +28 -0
  214. package/src/internal/shims.ts +145 -0
  215. package/src/internal/types.ts +98 -0
  216. package/src/internal/uploads.ts +307 -0
  217. package/src/internal/utils/base64.ts +37 -0
  218. package/src/internal/utils/env.ts +18 -0
  219. package/src/internal/utils/log.ts +49 -0
  220. package/src/internal/utils/sleep.ts +3 -0
  221. package/src/internal/utils/uuid.ts +13 -0
  222. package/src/internal/utils/values.ts +94 -0
  223. package/src/internal/utils.ts +8 -0
  224. package/src/lib/.keep +4 -0
  225. package/src/resource.ts +11 -0
  226. package/src/resources/calls.ts +118 -0
  227. package/src/resources/index.ts +3 -0
  228. package/src/tsconfig.json +11 -0
  229. package/src/uploads.ts +1 -0
  230. package/src/version.ts +1 -0
  231. package/uploads.d.mts +2 -0
  232. package/uploads.d.mts.map +1 -0
  233. package/uploads.d.ts +2 -0
  234. package/uploads.d.ts.map +1 -0
  235. package/uploads.js +6 -0
  236. package/uploads.js.map +1 -0
  237. package/uploads.mjs +2 -0
  238. package/uploads.mjs.map +1 -0
  239. package/version.d.mts +2 -0
  240. package/version.d.mts.map +1 -0
  241. package/version.d.ts +2 -0
  242. package/version.d.ts.map +1 -0
  243. package/version.js +5 -0
  244. package/version.js.map +1 -0
  245. package/version.mjs +2 -0
  246. package/version.mjs.map +1 -0
package/src/client.ts ADDED
@@ -0,0 +1,646 @@
1
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+
3
+ import type { RequestInit, RequestInfo, BodyInit } from './internal/builtin-types';
4
+ import type { HTTPMethod, PromiseOrValue, MergedRequestInit } from './internal/types';
5
+ import { uuid4 } from './internal/utils/uuid';
6
+ import { validatePositiveInteger, isAbsoluteURL } from './internal/utils/values';
7
+ import { sleep } from './internal/utils/sleep';
8
+ import { castToError, isAbortError } from './internal/errors';
9
+ import type { APIResponseProps } from './internal/parse';
10
+ import { getPlatformHeaders } from './internal/detect-platform';
11
+ import * as Shims from './internal/shims';
12
+ import * as Opts from './internal/request-options';
13
+ import { VERSION } from './version';
14
+ import * as Errors from './error';
15
+ import * as Uploads from './uploads';
16
+ import * as API from './resources/index';
17
+ import { APIPromise } from './api-promise';
18
+ import { type Fetch } from './internal/builtin-types';
19
+ import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers';
20
+ import { FinalRequestOptions, RequestOptions } from './internal/request-options';
21
+ import { CallCreateParams, CallCreateResponse, Calls } from './resources/calls';
22
+ import { readEnv } from './internal/utils/env';
23
+ import { logger } from './internal/utils/log';
24
+ import { isEmptyObj } from './internal/utils/values';
25
+
26
+ const safeJSON = (text: string) => {
27
+ try {
28
+ return JSON.parse(text);
29
+ } catch (err) {
30
+ return undefined;
31
+ }
32
+ };
33
+
34
+ type LogFn = (message: string, ...rest: unknown[]) => void;
35
+ export type Logger = {
36
+ error: LogFn;
37
+ warn: LogFn;
38
+ info: LogFn;
39
+ debug: LogFn;
40
+ };
41
+ export type LogLevel = 'off' | 'error' | 'warn' | 'info' | 'debug';
42
+ const isLogLevel = (key: string | undefined): key is LogLevel => {
43
+ const levels: Record<LogLevel, true> = {
44
+ off: true,
45
+ error: true,
46
+ warn: true,
47
+ info: true,
48
+ debug: true,
49
+ };
50
+ return key! in levels;
51
+ };
52
+
53
+ export interface ClientOptions {
54
+ /**
55
+ * JWT token for authentication
56
+ */
57
+ bearerToken?: string | undefined;
58
+
59
+ /**
60
+ * Override the default base URL for the API, e.g., "https://api.example.com/v2/"
61
+ *
62
+ * Defaults to process.env['PETSTORE_BASE_URL'].
63
+ */
64
+ baseURL?: string | null | undefined;
65
+
66
+ /**
67
+ * The maximum amount of time (in milliseconds) that the client should wait for a response
68
+ * from the server before timing out a single request.
69
+ *
70
+ * Note that request timeouts are retried by default, so in a worst-case scenario you may wait
71
+ * much longer than this timeout before the promise succeeds or fails.
72
+ */
73
+ timeout?: number | undefined;
74
+ /**
75
+ * Additional `RequestInit` options to be passed to `fetch` calls.
76
+ * Properties will be overridden by per-request `fetchOptions`.
77
+ */
78
+ fetchOptions?: MergedRequestInit | undefined;
79
+
80
+ /**
81
+ * Specify a custom `fetch` function implementation.
82
+ *
83
+ * If not provided, we expect that `fetch` is defined globally.
84
+ */
85
+ fetch?: Fetch | undefined;
86
+
87
+ /**
88
+ * The maximum number of times that the client will retry a request in case of a
89
+ * temporary failure, like a network error or a 5XX error from the server.
90
+ *
91
+ * @default 2
92
+ */
93
+ maxRetries?: number | undefined;
94
+
95
+ /**
96
+ * Default headers to include with every request to the API.
97
+ *
98
+ * These can be removed in individual requests by explicitly setting the
99
+ * header to `null` in request options.
100
+ */
101
+ defaultHeaders?: HeadersLike | undefined;
102
+
103
+ /**
104
+ * Default query parameters to include with every request to the API.
105
+ *
106
+ * These can be removed in individual requests by explicitly setting the
107
+ * param to `undefined` in request options.
108
+ */
109
+ defaultQuery?: Record<string, string | undefined> | undefined;
110
+
111
+ /**
112
+ * Set the log level.
113
+ *
114
+ * Defaults to process.env['PETSTORE_LOG'].
115
+ */
116
+ logLevel?: LogLevel | undefined | null;
117
+
118
+ /**
119
+ * Set the logger.
120
+ *
121
+ * Defaults to globalThis.console.
122
+ */
123
+ logger?: Logger | undefined | null;
124
+ }
125
+
126
+ type FinalizedRequestInit = RequestInit & { headers: Headers };
127
+
128
+ /**
129
+ * API Client for interfacing with the Petstore API.
130
+ */
131
+ export class Petstore {
132
+ bearerToken: string;
133
+
134
+ baseURL: string;
135
+ maxRetries: number;
136
+ timeout: number;
137
+ logger: Logger | undefined;
138
+ logLevel: LogLevel | undefined;
139
+ fetchOptions: MergedRequestInit | undefined;
140
+
141
+ private fetch: Fetch;
142
+ #encoder: Opts.RequestEncoder;
143
+ protected idempotencyHeader?: string;
144
+ private _options: ClientOptions;
145
+
146
+ /**
147
+ * API Client for interfacing with the Petstore API.
148
+ *
149
+ * @param {string | undefined} [opts.bearerToken=process.env['ROARK_API_BEARER_TOKEN'] ?? undefined]
150
+ * @param {string} [opts.baseURL=process.env['PETSTORE_BASE_URL'] ?? https://petstore3.swagger.io/api/v3] - Override the default base URL for the API.
151
+ * @param {number} [opts.timeout=1 minute] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
152
+ * @param {MergedRequestInit} [opts.fetchOptions] - Additional `RequestInit` options to be passed to `fetch` calls.
153
+ * @param {Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.
154
+ * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.
155
+ * @param {HeadersLike} opts.defaultHeaders - Default headers to include with every request to the API.
156
+ * @param {Record<string, string | undefined>} opts.defaultQuery - Default query parameters to include with every request to the API.
157
+ */
158
+ constructor({
159
+ baseURL = readEnv('PETSTORE_BASE_URL'),
160
+ bearerToken = readEnv('ROARK_API_BEARER_TOKEN'),
161
+ ...opts
162
+ }: ClientOptions = {}) {
163
+ if (bearerToken === undefined) {
164
+ throw new Errors.PetstoreError(
165
+ "The ROARK_API_BEARER_TOKEN environment variable is missing or empty; either provide it, or instantiate the Petstore client with an bearerToken option, like new Petstore({ bearerToken: 'My Bearer Token' }).",
166
+ );
167
+ }
168
+
169
+ const options: ClientOptions = {
170
+ bearerToken,
171
+ ...opts,
172
+ baseURL: baseURL || `https://petstore3.swagger.io/api/v3`,
173
+ };
174
+
175
+ this.baseURL = options.baseURL!;
176
+ this.timeout = options.timeout ?? Petstore.DEFAULT_TIMEOUT /* 1 minute */;
177
+ this.logger = options.logger ?? console;
178
+ if (options.logLevel != null) {
179
+ this.logLevel = options.logLevel;
180
+ } else {
181
+ const envLevel = readEnv('PETSTORE_LOG');
182
+ if (isLogLevel(envLevel)) {
183
+ this.logLevel = envLevel;
184
+ }
185
+ }
186
+ this.fetchOptions = options.fetchOptions;
187
+ this.maxRetries = options.maxRetries ?? 2;
188
+ this.fetch = options.fetch ?? Shims.getDefaultFetch();
189
+ this.#encoder = Opts.FallbackEncoder;
190
+
191
+ this._options = options;
192
+
193
+ this.bearerToken = bearerToken;
194
+ }
195
+
196
+ protected defaultQuery(): Record<string, string | undefined> | undefined {
197
+ return this._options.defaultQuery;
198
+ }
199
+
200
+ protected validateHeaders({ values, nulls }: NullableHeaders) {
201
+ return;
202
+ }
203
+
204
+ protected authHeaders(opts: FinalRequestOptions): Headers | undefined {
205
+ return new Headers({ Authorization: `Bearer ${this.bearerToken}` });
206
+ }
207
+
208
+ /**
209
+ * Basic re-implementation of `qs.stringify` for primitive types.
210
+ */
211
+ protected stringifyQuery(query: Record<string, unknown>): string {
212
+ return Object.entries(query)
213
+ .filter(([_, value]) => typeof value !== 'undefined')
214
+ .map(([key, value]) => {
215
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
216
+ return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
217
+ }
218
+ if (value === null) {
219
+ return `${encodeURIComponent(key)}=`;
220
+ }
221
+ throw new Errors.PetstoreError(
222
+ `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.`,
223
+ );
224
+ })
225
+ .join('&');
226
+ }
227
+
228
+ private getUserAgent(): string {
229
+ return `${this.constructor.name}/JS ${VERSION}`;
230
+ }
231
+
232
+ protected defaultIdempotencyKey(): string {
233
+ return `stainless-node-retry-${uuid4()}`;
234
+ }
235
+
236
+ protected makeStatusError(
237
+ status: number,
238
+ error: Object,
239
+ message: string | undefined,
240
+ headers: Headers,
241
+ ): Errors.APIError {
242
+ return Errors.APIError.generate(status, error, message, headers);
243
+ }
244
+
245
+ buildURL(path: string, query: Record<string, unknown> | null | undefined): string {
246
+ const url =
247
+ isAbsoluteURL(path) ?
248
+ new URL(path)
249
+ : new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
250
+
251
+ const defaultQuery = this.defaultQuery();
252
+ if (!isEmptyObj(defaultQuery)) {
253
+ query = { ...defaultQuery, ...query };
254
+ }
255
+
256
+ if (typeof query === 'object' && query && !Array.isArray(query)) {
257
+ url.search = this.stringifyQuery(query as Record<string, unknown>);
258
+ }
259
+
260
+ return url.toString();
261
+ }
262
+
263
+ private calculateContentLength(body: unknown): string | null {
264
+ if (typeof body === 'string') {
265
+ if (typeof (globalThis as any).Buffer !== 'undefined') {
266
+ return (globalThis as any).Buffer.byteLength(body, 'utf8').toString();
267
+ }
268
+
269
+ if (typeof (globalThis as any).TextEncoder !== 'undefined') {
270
+ const encoder = new (globalThis as any).TextEncoder();
271
+ const encoded = encoder.encode(body);
272
+ return encoded.length.toString();
273
+ }
274
+ } else if (ArrayBuffer.isView(body)) {
275
+ return body.byteLength.toString();
276
+ }
277
+
278
+ return null;
279
+ }
280
+
281
+ /**
282
+ * Used as a callback for mutating the given `FinalRequestOptions` object.
283
+ */
284
+ protected async prepareOptions(options: FinalRequestOptions): Promise<void> {}
285
+
286
+ /**
287
+ * Used as a callback for mutating the given `RequestInit` object.
288
+ *
289
+ * This is useful for cases where you want to add certain headers based off of
290
+ * the request properties, e.g. `method` or `url`.
291
+ */
292
+ protected async prepareRequest(
293
+ request: RequestInit,
294
+ { url, options }: { url: string; options: FinalRequestOptions },
295
+ ): Promise<void> {}
296
+
297
+ get<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> {
298
+ return this.methodRequest('get', path, opts);
299
+ }
300
+
301
+ post<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> {
302
+ return this.methodRequest('post', path, opts);
303
+ }
304
+
305
+ patch<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> {
306
+ return this.methodRequest('patch', path, opts);
307
+ }
308
+
309
+ put<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> {
310
+ return this.methodRequest('put', path, opts);
311
+ }
312
+
313
+ delete<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> {
314
+ return this.methodRequest('delete', path, opts);
315
+ }
316
+
317
+ private methodRequest<Rsp>(
318
+ method: HTTPMethod,
319
+ path: string,
320
+ opts?: PromiseOrValue<RequestOptions>,
321
+ ): APIPromise<Rsp> {
322
+ return this.request(
323
+ Promise.resolve(opts).then((opts) => {
324
+ return { method, path, ...opts };
325
+ }),
326
+ );
327
+ }
328
+
329
+ request<Rsp>(
330
+ options: PromiseOrValue<FinalRequestOptions>,
331
+ remainingRetries: number | null = null,
332
+ ): APIPromise<Rsp> {
333
+ return new APIPromise(this, this.makeRequest(options, remainingRetries));
334
+ }
335
+
336
+ private async makeRequest(
337
+ optionsInput: PromiseOrValue<FinalRequestOptions>,
338
+ retriesRemaining: number | null,
339
+ ): Promise<APIResponseProps> {
340
+ const options = await optionsInput;
341
+ const maxRetries = options.maxRetries ?? this.maxRetries;
342
+ if (retriesRemaining == null) {
343
+ retriesRemaining = maxRetries;
344
+ }
345
+
346
+ await this.prepareOptions(options);
347
+
348
+ const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });
349
+
350
+ await this.prepareRequest(req, { url, options });
351
+
352
+ logger(this).debug('request', url, options, req.headers);
353
+
354
+ if (options.signal?.aborted) {
355
+ throw new Errors.APIUserAbortError();
356
+ }
357
+
358
+ const controller = new AbortController();
359
+ const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);
360
+
361
+ if (response instanceof Error) {
362
+ if (options.signal?.aborted) {
363
+ throw new Errors.APIUserAbortError();
364
+ }
365
+ if (retriesRemaining) {
366
+ return this.retryRequest(options, retriesRemaining);
367
+ }
368
+ if (isAbortError(response)) {
369
+ throw new Errors.APIConnectionTimeoutError();
370
+ }
371
+ // detect native connection timeout errors
372
+ // deno throws "TypeError: error sending request for url (https://example/): client error (Connect): tcp connect error: Operation timed out (os error 60): Operation timed out (os error 60)"
373
+ // undici throws "TypeError: fetch failed" with cause "ConnectTimeoutError: Connect Timeout Error (attempted address: example:443, timeout: 1ms)"
374
+ // others do not provide enough information to distinguish timeouts from other connection errors
375
+ if (/timed? ?out/i.test(String(response) + ('cause' in response ? String(response.cause) : ''))) {
376
+ throw new Errors.APIConnectionTimeoutError();
377
+ }
378
+ throw new Errors.APIConnectionError({ cause: response });
379
+ }
380
+
381
+ if (!response.ok) {
382
+ if (retriesRemaining && this.shouldRetry(response)) {
383
+ const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
384
+ logger(this).debug(`response (error; ${retryMessage})`, response.status, url, response.headers);
385
+ return this.retryRequest(options, retriesRemaining, response.headers);
386
+ }
387
+
388
+ const errText = await response.text().catch((err: any) => castToError(err).message);
389
+ const errJSON = safeJSON(errText);
390
+ const errMessage = errJSON ? undefined : errText;
391
+ const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;
392
+
393
+ logger(this).debug(
394
+ `response (error; ${retryMessage})`,
395
+ response.status,
396
+ url,
397
+ response.headers,
398
+ errMessage,
399
+ );
400
+
401
+ const err = this.makeStatusError(response.status, errJSON, errMessage, response.headers);
402
+ throw err;
403
+ }
404
+
405
+ return { response, options, controller };
406
+ }
407
+
408
+ async fetchWithTimeout(
409
+ url: RequestInfo,
410
+ init: RequestInit | undefined,
411
+ ms: number,
412
+ controller: AbortController,
413
+ ): Promise<Response> {
414
+ const { signal, method, ...options } = init || {};
415
+ if (signal) signal.addEventListener('abort', () => controller.abort());
416
+
417
+ const timeout = setTimeout(() => controller.abort(), ms);
418
+
419
+ const isReadableBody = Shims.isReadableLike(options.body);
420
+
421
+ const fetchOptions: RequestInit = {
422
+ signal: controller.signal as any,
423
+ ...(isReadableBody ? { duplex: 'half' } : {}),
424
+ method: 'GET',
425
+ ...options,
426
+ };
427
+ if (method) {
428
+ // Custom methods like 'patch' need to be uppercased
429
+ // See https://github.com/nodejs/undici/issues/2294
430
+ fetchOptions.method = method.toUpperCase();
431
+ }
432
+
433
+ return (
434
+ // use undefined this binding; fetch errors if bound to something else in browser/cloudflare
435
+ this.fetch.call(undefined, url, fetchOptions).finally(() => {
436
+ clearTimeout(timeout);
437
+ })
438
+ );
439
+ }
440
+
441
+ private shouldRetry(response: Response): boolean {
442
+ // Note this is not a standard header.
443
+ const shouldRetryHeader = response.headers.get('x-should-retry');
444
+
445
+ // If the server explicitly says whether or not to retry, obey.
446
+ if (shouldRetryHeader === 'true') return true;
447
+ if (shouldRetryHeader === 'false') return false;
448
+
449
+ // Retry on request timeouts.
450
+ if (response.status === 408) return true;
451
+
452
+ // Retry on lock timeouts.
453
+ if (response.status === 409) return true;
454
+
455
+ // Retry on rate limits.
456
+ if (response.status === 429) return true;
457
+
458
+ // Retry internal errors.
459
+ if (response.status >= 500) return true;
460
+
461
+ return false;
462
+ }
463
+
464
+ private async retryRequest(
465
+ options: FinalRequestOptions,
466
+ retriesRemaining: number,
467
+ responseHeaders?: Headers | undefined,
468
+ ): Promise<APIResponseProps> {
469
+ let timeoutMillis: number | undefined;
470
+
471
+ // Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it.
472
+ const retryAfterMillisHeader = responseHeaders?.get('retry-after-ms');
473
+ if (retryAfterMillisHeader) {
474
+ const timeoutMs = parseFloat(retryAfterMillisHeader);
475
+ if (!Number.isNaN(timeoutMs)) {
476
+ timeoutMillis = timeoutMs;
477
+ }
478
+ }
479
+
480
+ // About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
481
+ const retryAfterHeader = responseHeaders?.get('retry-after');
482
+ if (retryAfterHeader && !timeoutMillis) {
483
+ const timeoutSeconds = parseFloat(retryAfterHeader);
484
+ if (!Number.isNaN(timeoutSeconds)) {
485
+ timeoutMillis = timeoutSeconds * 1000;
486
+ } else {
487
+ timeoutMillis = Date.parse(retryAfterHeader) - Date.now();
488
+ }
489
+ }
490
+
491
+ // If the API asks us to wait a certain amount of time (and it's a reasonable amount),
492
+ // just do what it says, but otherwise calculate a default
493
+ if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) {
494
+ const maxRetries = options.maxRetries ?? this.maxRetries;
495
+ timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
496
+ }
497
+ await sleep(timeoutMillis);
498
+
499
+ return this.makeRequest(options, retriesRemaining - 1);
500
+ }
501
+
502
+ private calculateDefaultRetryTimeoutMillis(retriesRemaining: number, maxRetries: number): number {
503
+ const initialRetryDelay = 0.5;
504
+ const maxRetryDelay = 8.0;
505
+
506
+ const numRetries = maxRetries - retriesRemaining;
507
+
508
+ // Apply exponential backoff, but not more than the max.
509
+ const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);
510
+
511
+ // Apply some jitter, take up to at most 25 percent of the retry time.
512
+ const jitter = 1 - Math.random() * 0.25;
513
+
514
+ return sleepSeconds * jitter * 1000;
515
+ }
516
+
517
+ buildRequest(
518
+ options: FinalRequestOptions,
519
+ { retryCount = 0 }: { retryCount?: number } = {},
520
+ ): { req: FinalizedRequestInit; url: string; timeout: number } {
521
+ const { method, path, query } = options;
522
+
523
+ const url = this.buildURL(path!, query as Record<string, unknown>);
524
+ if ('timeout' in options) validatePositiveInteger('timeout', options.timeout);
525
+ const timeout = options.timeout ?? this.timeout;
526
+ const { bodyHeaders, body } = this.buildBody({ options });
527
+ const reqHeaders = this.buildHeaders({ options, method, bodyHeaders, retryCount });
528
+
529
+ const req: FinalizedRequestInit = {
530
+ method,
531
+ headers: reqHeaders,
532
+ ...(options.signal && { signal: options.signal }),
533
+ ...((globalThis as any).ReadableStream &&
534
+ body instanceof (globalThis as any).ReadableStream && { duplex: 'half' }),
535
+ ...(body && { body }),
536
+ ...((this.fetchOptions as any) ?? {}),
537
+ ...((options.fetchOptions as any) ?? {}),
538
+ };
539
+
540
+ return { req, url, timeout };
541
+ }
542
+
543
+ private buildHeaders({
544
+ options,
545
+ method,
546
+ bodyHeaders,
547
+ retryCount,
548
+ }: {
549
+ options: FinalRequestOptions;
550
+ method: HTTPMethod;
551
+ bodyHeaders: HeadersLike;
552
+ retryCount: number;
553
+ }): Headers {
554
+ let idempotencyHeaders: HeadersLike = {};
555
+ if (this.idempotencyHeader && method !== 'get') {
556
+ if (!options.idempotencyKey) options.idempotencyKey = this.defaultIdempotencyKey();
557
+ idempotencyHeaders[this.idempotencyHeader] = options.idempotencyKey;
558
+ }
559
+
560
+ const headers = buildHeaders([
561
+ idempotencyHeaders,
562
+ {
563
+ Accept: 'application/json',
564
+ 'User-Agent': this.getUserAgent(),
565
+ 'X-Stainless-Retry-Count': String(retryCount),
566
+ ...getPlatformHeaders(),
567
+ },
568
+ this.authHeaders(options),
569
+ this._options.defaultHeaders,
570
+ bodyHeaders,
571
+ options.headers,
572
+ ]);
573
+
574
+ this.validateHeaders(headers);
575
+
576
+ return headers.values;
577
+ }
578
+
579
+ private buildBody({ options: { body, headers: rawHeaders } }: { options: FinalRequestOptions }): {
580
+ bodyHeaders: HeadersLike;
581
+ body: BodyInit | undefined;
582
+ } {
583
+ if (!body) {
584
+ return { bodyHeaders: undefined, body: undefined };
585
+ }
586
+ const headers = buildHeaders([rawHeaders]);
587
+ if (
588
+ // Pass raw type verbatim
589
+ ArrayBuffer.isView(body) ||
590
+ body instanceof ArrayBuffer ||
591
+ body instanceof DataView ||
592
+ (typeof body === 'string' &&
593
+ // Preserve legacy string encoding behavior for now
594
+ headers.values.has('content-type')) ||
595
+ // `Blob` is superset of `File`
596
+ body instanceof Blob ||
597
+ // `FormData` -> `multipart/form-data`
598
+ body instanceof FormData ||
599
+ // `URLSearchParams` -> `application/x-www-form-urlencoded`
600
+ body instanceof URLSearchParams ||
601
+ // Send chunked stream (each chunk has own `length`)
602
+ ((globalThis as any).ReadableStream && body instanceof (globalThis as any).ReadableStream)
603
+ ) {
604
+ return { bodyHeaders: undefined, body: body as BodyInit };
605
+ } else if (
606
+ typeof body === 'object' &&
607
+ (Symbol.asyncIterator in body ||
608
+ (Symbol.iterator in body && 'next' in body && typeof body.next === 'function'))
609
+ ) {
610
+ return { bodyHeaders: undefined, body: Shims.ReadableStreamFrom(body as AsyncIterable<Uint8Array>) };
611
+ } else {
612
+ return this.#encoder({ body, headers });
613
+ }
614
+ }
615
+
616
+ static Petstore = this;
617
+ static DEFAULT_TIMEOUT = 60000; // 1 minute
618
+
619
+ static PetstoreError = Errors.PetstoreError;
620
+ static APIError = Errors.APIError;
621
+ static APIConnectionError = Errors.APIConnectionError;
622
+ static APIConnectionTimeoutError = Errors.APIConnectionTimeoutError;
623
+ static APIUserAbortError = Errors.APIUserAbortError;
624
+ static NotFoundError = Errors.NotFoundError;
625
+ static ConflictError = Errors.ConflictError;
626
+ static RateLimitError = Errors.RateLimitError;
627
+ static BadRequestError = Errors.BadRequestError;
628
+ static AuthenticationError = Errors.AuthenticationError;
629
+ static InternalServerError = Errors.InternalServerError;
630
+ static PermissionDeniedError = Errors.PermissionDeniedError;
631
+ static UnprocessableEntityError = Errors.UnprocessableEntityError;
632
+
633
+ static toFile = Uploads.toFile;
634
+
635
+ calls: API.Calls = new API.Calls(this);
636
+ }
637
+ Petstore.Calls = Calls;
638
+ export declare namespace Petstore {
639
+ export type RequestOptions = Opts.RequestOptions;
640
+
641
+ export {
642
+ Calls as Calls,
643
+ type CallCreateResponse as CallCreateResponse,
644
+ type CallCreateParams as CallCreateParams,
645
+ };
646
+ }