| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990 |
- "use strict";
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
- if (kind === "m") throw new TypeError("Private method is not writable");
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
- };
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
- };
- var _AbstractPage_client;
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.isObj = exports.toFloat32Array = exports.toBase64 = exports.getHeader = exports.getRequiredHeader = exports.isHeadersProtocol = exports.isRunningInBrowser = exports.debug = exports.hasOwn = exports.isEmptyObj = exports.maybeCoerceBoolean = exports.maybeCoerceFloat = exports.maybeCoerceInteger = exports.coerceBoolean = exports.coerceFloat = exports.coerceInteger = exports.readEnv = exports.ensurePresent = exports.castToError = exports.sleep = exports.safeJSON = exports.isRequestOptions = exports.createResponseHeaders = exports.PagePromise = exports.AbstractPage = exports.APIClient = exports.APIPromise = exports.createForm = exports.multipartFormRequestOptions = exports.maybeMultipartFormRequestOptions = void 0;
- const version_1 = require("./version.js");
- const streaming_1 = require("./streaming.js");
- const error_1 = require("./error.js");
- const index_1 = require("./_shims/index.js");
- // try running side effects outside of _shims/index to workaround https://github.com/vercel/next.js/issues/76881
- (0, index_1.init)();
- const uploads_1 = require("./uploads.js");
- var uploads_2 = require("./uploads.js");
- Object.defineProperty(exports, "maybeMultipartFormRequestOptions", { enumerable: true, get: function () { return uploads_2.maybeMultipartFormRequestOptions; } });
- Object.defineProperty(exports, "multipartFormRequestOptions", { enumerable: true, get: function () { return uploads_2.multipartFormRequestOptions; } });
- Object.defineProperty(exports, "createForm", { enumerable: true, get: function () { return uploads_2.createForm; } });
- async function defaultParseResponse(props) {
- const { response } = props;
- if (props.options.stream) {
- debug('response', response.status, response.url, response.headers, response.body);
- // Note: there is an invariant here that isn't represented in the type system
- // that if you set `stream: true` the response type must also be `Stream<T>`
- if (props.options.__streamClass) {
- return props.options.__streamClass.fromSSEResponse(response, props.controller);
- }
- return streaming_1.Stream.fromSSEResponse(response, props.controller);
- }
- // fetch refuses to read the body when the status code is 204.
- if (response.status === 204) {
- return null;
- }
- if (props.options.__binaryResponse) {
- return response;
- }
- const contentType = response.headers.get('content-type');
- const mediaType = contentType?.split(';')[0]?.trim();
- const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+json');
- if (isJSON) {
- const json = await response.json();
- debug('response', response.status, response.url, response.headers, json);
- return _addRequestID(json, response);
- }
- const text = await response.text();
- debug('response', response.status, response.url, response.headers, text);
- // TODO handle blob, arraybuffer, other content types, etc.
- return text;
- }
- function _addRequestID(value, response) {
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
- return value;
- }
- return Object.defineProperty(value, '_request_id', {
- value: response.headers.get('x-request-id'),
- enumerable: false,
- });
- }
- /**
- * A subclass of `Promise` providing additional helper methods
- * for interacting with the SDK.
- */
- class APIPromise extends Promise {
- constructor(responsePromise, parseResponse = defaultParseResponse) {
- super((resolve) => {
- // this is maybe a bit weird but this has to be a no-op to not implicitly
- // parse the response body; instead .then, .catch, .finally are overridden
- // to parse the response
- resolve(null);
- });
- this.responsePromise = responsePromise;
- this.parseResponse = parseResponse;
- }
- _thenUnwrap(transform) {
- return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));
- }
- /**
- * Gets the raw `Response` instance instead of parsing the response
- * data.
- *
- * If you want to parse the response body but still get the `Response`
- * instance, you can use {@link withResponse()}.
- *
- * 👋 Getting the wrong TypeScript type for `Response`?
- * Try setting `"moduleResolution": "NodeNext"` if you can,
- * or add one of these imports before your first `import … from 'openai'`:
- * - `import 'openai/shims/node'` (if you're running on Node)
- * - `import 'openai/shims/web'` (otherwise)
- */
- asResponse() {
- return this.responsePromise.then((p) => p.response);
- }
- /**
- * Gets the parsed response data, the raw `Response` instance and the ID of the request,
- * returned via the X-Request-ID header which is useful for debugging requests and reporting
- * issues to OpenAI.
- *
- * If you just want to get the raw `Response` instance without parsing it,
- * you can use {@link asResponse()}.
- *
- *
- * 👋 Getting the wrong TypeScript type for `Response`?
- * Try setting `"moduleResolution": "NodeNext"` if you can,
- * or add one of these imports before your first `import … from 'openai'`:
- * - `import 'openai/shims/node'` (if you're running on Node)
- * - `import 'openai/shims/web'` (otherwise)
- */
- async withResponse() {
- const [data, response] = await Promise.all([this.parse(), this.asResponse()]);
- return { data, response, request_id: response.headers.get('x-request-id') };
- }
- parse() {
- if (!this.parsedPromise) {
- this.parsedPromise = this.responsePromise.then(this.parseResponse);
- }
- return this.parsedPromise;
- }
- then(onfulfilled, onrejected) {
- return this.parse().then(onfulfilled, onrejected);
- }
- catch(onrejected) {
- return this.parse().catch(onrejected);
- }
- finally(onfinally) {
- return this.parse().finally(onfinally);
- }
- }
- exports.APIPromise = APIPromise;
- class APIClient {
- constructor({ baseURL, maxRetries = 2, timeout = 600000, // 10 minutes
- httpAgent, fetch: overriddenFetch, }) {
- this.baseURL = baseURL;
- this.maxRetries = validatePositiveInteger('maxRetries', maxRetries);
- this.timeout = validatePositiveInteger('timeout', timeout);
- this.httpAgent = httpAgent;
- this.fetch = overriddenFetch ?? index_1.fetch;
- }
- authHeaders(opts) {
- return {};
- }
- /**
- * Override this to add your own default headers, for example:
- *
- * {
- * ...super.defaultHeaders(),
- * Authorization: 'Bearer 123',
- * }
- */
- defaultHeaders(opts) {
- return {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- 'User-Agent': this.getUserAgent(),
- ...getPlatformHeaders(),
- ...this.authHeaders(opts),
- };
- }
- /**
- * Override this to add your own headers validation:
- */
- validateHeaders(headers, customHeaders) { }
- defaultIdempotencyKey() {
- return `stainless-node-retry-${uuid4()}`;
- }
- get(path, opts) {
- return this.methodRequest('get', path, opts);
- }
- post(path, opts) {
- return this.methodRequest('post', path, opts);
- }
- patch(path, opts) {
- return this.methodRequest('patch', path, opts);
- }
- put(path, opts) {
- return this.methodRequest('put', path, opts);
- }
- delete(path, opts) {
- return this.methodRequest('delete', path, opts);
- }
- methodRequest(method, path, opts) {
- return this.request(Promise.resolve(opts).then(async (opts) => {
- const body = opts && (0, uploads_1.isBlobLike)(opts?.body) ? new DataView(await opts.body.arrayBuffer())
- : opts?.body instanceof DataView ? opts.body
- : opts?.body instanceof ArrayBuffer ? new DataView(opts.body)
- : opts && ArrayBuffer.isView(opts?.body) ? new DataView(opts.body.buffer)
- : opts?.body;
- return { method, path, ...opts, body };
- }));
- }
- getAPIList(path, Page, opts) {
- return this.requestAPIList(Page, { method: 'get', path, ...opts });
- }
- calculateContentLength(body) {
- if (typeof body === 'string') {
- if (typeof Buffer !== 'undefined') {
- return Buffer.byteLength(body, 'utf8').toString();
- }
- if (typeof TextEncoder !== 'undefined') {
- const encoder = new TextEncoder();
- const encoded = encoder.encode(body);
- return encoded.length.toString();
- }
- }
- else if (ArrayBuffer.isView(body)) {
- return body.byteLength.toString();
- }
- return null;
- }
- buildRequest(inputOptions, { retryCount = 0 } = {}) {
- const options = { ...inputOptions };
- const { method, path, query, headers: headers = {} } = options;
- const body = ArrayBuffer.isView(options.body) || (options.__binaryRequest && typeof options.body === 'string') ?
- options.body
- : (0, uploads_1.isMultipartBody)(options.body) ? options.body.body
- : options.body ? JSON.stringify(options.body, null, 2)
- : null;
- const contentLength = this.calculateContentLength(body);
- const url = this.buildURL(path, query);
- if ('timeout' in options)
- validatePositiveInteger('timeout', options.timeout);
- options.timeout = options.timeout ?? this.timeout;
- const httpAgent = options.httpAgent ?? this.httpAgent ?? (0, index_1.getDefaultAgent)(url);
- const minAgentTimeout = options.timeout + 1000;
- if (typeof httpAgent?.options?.timeout === 'number' &&
- minAgentTimeout > (httpAgent.options.timeout ?? 0)) {
- // Allow any given request to bump our agent active socket timeout.
- // This may seem strange, but leaking active sockets should be rare and not particularly problematic,
- // and without mutating agent we would need to create more of them.
- // This tradeoff optimizes for performance.
- httpAgent.options.timeout = minAgentTimeout;
- }
- if (this.idempotencyHeader && method !== 'get') {
- if (!inputOptions.idempotencyKey)
- inputOptions.idempotencyKey = this.defaultIdempotencyKey();
- headers[this.idempotencyHeader] = inputOptions.idempotencyKey;
- }
- const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });
- const req = {
- method,
- ...(body && { body: body }),
- headers: reqHeaders,
- ...(httpAgent && { agent: httpAgent }),
- // @ts-ignore node-fetch uses a custom AbortSignal type that is
- // not compatible with standard web types
- signal: options.signal ?? null,
- };
- return { req, url, timeout: options.timeout };
- }
- buildHeaders({ options, headers, contentLength, retryCount, }) {
- const reqHeaders = {};
- if (contentLength) {
- reqHeaders['content-length'] = contentLength;
- }
- const defaultHeaders = this.defaultHeaders(options);
- applyHeadersMut(reqHeaders, defaultHeaders);
- applyHeadersMut(reqHeaders, headers);
- // let builtin fetch set the Content-Type for multipart bodies
- if ((0, uploads_1.isMultipartBody)(options.body) && index_1.kind !== 'node') {
- delete reqHeaders['content-type'];
- }
- // Don't set theses headers if they were already set or removed through default headers or by the caller.
- // We check `defaultHeaders` and `headers`, which can contain nulls, instead of `reqHeaders` to account
- // for the removal case.
- if ((0, exports.getHeader)(defaultHeaders, 'x-stainless-retry-count') === undefined &&
- (0, exports.getHeader)(headers, 'x-stainless-retry-count') === undefined) {
- reqHeaders['x-stainless-retry-count'] = String(retryCount);
- }
- if ((0, exports.getHeader)(defaultHeaders, 'x-stainless-timeout') === undefined &&
- (0, exports.getHeader)(headers, 'x-stainless-timeout') === undefined &&
- options.timeout) {
- reqHeaders['x-stainless-timeout'] = String(Math.trunc(options.timeout / 1000));
- }
- this.validateHeaders(reqHeaders, headers);
- return reqHeaders;
- }
- /**
- * Used as a callback for mutating the given `FinalRequestOptions` object.
- */
- async prepareOptions(options) { }
- /**
- * Used as a callback for mutating the given `RequestInit` object.
- *
- * This is useful for cases where you want to add certain headers based off of
- * the request properties, e.g. `method` or `url`.
- */
- async prepareRequest(request, { url, options }) { }
- parseHeaders(headers) {
- return (!headers ? {}
- : Symbol.iterator in headers ?
- Object.fromEntries(Array.from(headers).map((header) => [...header]))
- : { ...headers });
- }
- makeStatusError(status, error, message, headers) {
- return error_1.APIError.generate(status, error, message, headers);
- }
- request(options, remainingRetries = null) {
- return new APIPromise(this.makeRequest(options, remainingRetries));
- }
- async makeRequest(optionsInput, retriesRemaining) {
- const options = await optionsInput;
- const maxRetries = options.maxRetries ?? this.maxRetries;
- if (retriesRemaining == null) {
- retriesRemaining = maxRetries;
- }
- await this.prepareOptions(options);
- const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });
- await this.prepareRequest(req, { url, options });
- debug('request', url, options, req.headers);
- if (options.signal?.aborted) {
- throw new error_1.APIUserAbortError();
- }
- const controller = new AbortController();
- const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(exports.castToError);
- if (response instanceof Error) {
- if (options.signal?.aborted) {
- throw new error_1.APIUserAbortError();
- }
- if (retriesRemaining) {
- return this.retryRequest(options, retriesRemaining);
- }
- if (response.name === 'AbortError') {
- throw new error_1.APIConnectionTimeoutError();
- }
- throw new error_1.APIConnectionError({ cause: response });
- }
- const responseHeaders = (0, exports.createResponseHeaders)(response.headers);
- if (!response.ok) {
- if (retriesRemaining && this.shouldRetry(response)) {
- const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
- debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders);
- return this.retryRequest(options, retriesRemaining, responseHeaders);
- }
- const errText = await response.text().catch((e) => (0, exports.castToError)(e).message);
- const errJSON = (0, exports.safeJSON)(errText);
- const errMessage = errJSON ? undefined : errText;
- const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;
- debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);
- const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);
- throw err;
- }
- return { response, options, controller };
- }
- requestAPIList(Page, options) {
- const request = this.makeRequest(options, null);
- return new PagePromise(this, request, Page);
- }
- buildURL(path, query) {
- const url = isAbsoluteURL(path) ?
- new URL(path)
- : new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
- const defaultQuery = this.defaultQuery();
- if (!isEmptyObj(defaultQuery)) {
- query = { ...defaultQuery, ...query };
- }
- if (typeof query === 'object' && query && !Array.isArray(query)) {
- url.search = this.stringifyQuery(query);
- }
- return url.toString();
- }
- stringifyQuery(query) {
- return Object.entries(query)
- .filter(([_, value]) => typeof value !== 'undefined')
- .map(([key, value]) => {
- if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
- return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
- }
- if (value === null) {
- return `${encodeURIComponent(key)}=`;
- }
- throw new error_1.OpenAIError(`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.`);
- })
- .join('&');
- }
- async fetchWithTimeout(url, init, ms, controller) {
- const { signal, ...options } = init || {};
- if (signal)
- signal.addEventListener('abort', () => controller.abort());
- const timeout = setTimeout(() => controller.abort(), ms);
- const fetchOptions = {
- signal: controller.signal,
- ...options,
- };
- if (fetchOptions.method) {
- // Custom methods like 'patch' need to be uppercased
- // See https://github.com/nodejs/undici/issues/2294
- fetchOptions.method = fetchOptions.method.toUpperCase();
- }
- return (
- // use undefined this binding; fetch errors if bound to something else in browser/cloudflare
- this.fetch.call(undefined, url, fetchOptions).finally(() => {
- clearTimeout(timeout);
- }));
- }
- shouldRetry(response) {
- // Note this is not a standard header.
- const shouldRetryHeader = response.headers.get('x-should-retry');
- // If the server explicitly says whether or not to retry, obey.
- if (shouldRetryHeader === 'true')
- return true;
- if (shouldRetryHeader === 'false')
- return false;
- // Retry on request timeouts.
- if (response.status === 408)
- return true;
- // Retry on lock timeouts.
- if (response.status === 409)
- return true;
- // Retry on rate limits.
- if (response.status === 429)
- return true;
- // Retry internal errors.
- if (response.status >= 500)
- return true;
- return false;
- }
- async retryRequest(options, retriesRemaining, responseHeaders) {
- let timeoutMillis;
- // Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it.
- const retryAfterMillisHeader = responseHeaders?.['retry-after-ms'];
- if (retryAfterMillisHeader) {
- const timeoutMs = parseFloat(retryAfterMillisHeader);
- if (!Number.isNaN(timeoutMs)) {
- timeoutMillis = timeoutMs;
- }
- }
- // About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
- const retryAfterHeader = responseHeaders?.['retry-after'];
- if (retryAfterHeader && !timeoutMillis) {
- const timeoutSeconds = parseFloat(retryAfterHeader);
- if (!Number.isNaN(timeoutSeconds)) {
- timeoutMillis = timeoutSeconds * 1000;
- }
- else {
- timeoutMillis = Date.parse(retryAfterHeader) - Date.now();
- }
- }
- // If the API asks us to wait a certain amount of time (and it's a reasonable amount),
- // just do what it says, but otherwise calculate a default
- if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) {
- const maxRetries = options.maxRetries ?? this.maxRetries;
- timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
- }
- await (0, exports.sleep)(timeoutMillis);
- return this.makeRequest(options, retriesRemaining - 1);
- }
- calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {
- const initialRetryDelay = 0.5;
- const maxRetryDelay = 8.0;
- const numRetries = maxRetries - retriesRemaining;
- // Apply exponential backoff, but not more than the max.
- const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);
- // Apply some jitter, take up to at most 25 percent of the retry time.
- const jitter = 1 - Math.random() * 0.25;
- return sleepSeconds * jitter * 1000;
- }
- getUserAgent() {
- return `${this.constructor.name}/JS ${version_1.VERSION}`;
- }
- }
- exports.APIClient = APIClient;
- class AbstractPage {
- constructor(client, response, body, options) {
- _AbstractPage_client.set(this, void 0);
- __classPrivateFieldSet(this, _AbstractPage_client, client, "f");
- this.options = options;
- this.response = response;
- this.body = body;
- }
- hasNextPage() {
- const items = this.getPaginatedItems();
- if (!items.length)
- return false;
- return this.nextPageInfo() != null;
- }
- async getNextPage() {
- const nextInfo = this.nextPageInfo();
- if (!nextInfo) {
- throw new error_1.OpenAIError('No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.');
- }
- const nextOptions = { ...this.options };
- if ('params' in nextInfo && typeof nextOptions.query === 'object') {
- nextOptions.query = { ...nextOptions.query, ...nextInfo.params };
- }
- else if ('url' in nextInfo) {
- const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];
- for (const [key, value] of params) {
- nextInfo.url.searchParams.set(key, value);
- }
- nextOptions.query = undefined;
- nextOptions.path = nextInfo.url.toString();
- }
- return await __classPrivateFieldGet(this, _AbstractPage_client, "f").requestAPIList(this.constructor, nextOptions);
- }
- async *iterPages() {
- // eslint-disable-next-line @typescript-eslint/no-this-alias
- let page = this;
- yield page;
- while (page.hasNextPage()) {
- page = await page.getNextPage();
- yield page;
- }
- }
- async *[(_AbstractPage_client = new WeakMap(), Symbol.asyncIterator)]() {
- for await (const page of this.iterPages()) {
- for (const item of page.getPaginatedItems()) {
- yield item;
- }
- }
- }
- }
- exports.AbstractPage = AbstractPage;
- /**
- * This subclass of Promise will resolve to an instantiated Page once the request completes.
- *
- * It also implements AsyncIterable to allow auto-paginating iteration on an unawaited list call, eg:
- *
- * for await (const item of client.items.list()) {
- * console.log(item)
- * }
- */
- class PagePromise extends APIPromise {
- constructor(client, request, Page) {
- super(request, async (props) => new Page(client, props.response, await defaultParseResponse(props), props.options));
- }
- /**
- * Allow auto-paginating iteration on an unawaited list call, eg:
- *
- * for await (const item of client.items.list()) {
- * console.log(item)
- * }
- */
- async *[Symbol.asyncIterator]() {
- const page = await this;
- for await (const item of page) {
- yield item;
- }
- }
- }
- exports.PagePromise = PagePromise;
- const createResponseHeaders = (headers) => {
- return new Proxy(Object.fromEntries(
- // @ts-ignore
- headers.entries()), {
- get(target, name) {
- const key = name.toString();
- return target[key.toLowerCase()] || target[key];
- },
- });
- };
- exports.createResponseHeaders = createResponseHeaders;
- // This is required so that we can determine if a given object matches the RequestOptions
- // type at runtime. While this requires duplication, it is enforced by the TypeScript
- // compiler such that any missing / extraneous keys will cause an error.
- const requestOptionsKeys = {
- method: true,
- path: true,
- query: true,
- body: true,
- headers: true,
- maxRetries: true,
- stream: true,
- timeout: true,
- httpAgent: true,
- signal: true,
- idempotencyKey: true,
- __metadata: true,
- __binaryRequest: true,
- __binaryResponse: true,
- __streamClass: true,
- };
- const isRequestOptions = (obj) => {
- return (typeof obj === 'object' &&
- obj !== null &&
- !isEmptyObj(obj) &&
- Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k)));
- };
- exports.isRequestOptions = isRequestOptions;
- const getPlatformProperties = () => {
- if (typeof Deno !== 'undefined' && Deno.build != null) {
- return {
- 'X-Stainless-Lang': 'js',
- 'X-Stainless-Package-Version': version_1.VERSION,
- 'X-Stainless-OS': normalizePlatform(Deno.build.os),
- 'X-Stainless-Arch': normalizeArch(Deno.build.arch),
- 'X-Stainless-Runtime': 'deno',
- 'X-Stainless-Runtime-Version': typeof Deno.version === 'string' ? Deno.version : Deno.version?.deno ?? 'unknown',
- };
- }
- if (typeof EdgeRuntime !== 'undefined') {
- return {
- 'X-Stainless-Lang': 'js',
- 'X-Stainless-Package-Version': version_1.VERSION,
- 'X-Stainless-OS': 'Unknown',
- 'X-Stainless-Arch': `other:${EdgeRuntime}`,
- 'X-Stainless-Runtime': 'edge',
- 'X-Stainless-Runtime-Version': process.version,
- };
- }
- // Check if Node.js
- if (Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]') {
- return {
- 'X-Stainless-Lang': 'js',
- 'X-Stainless-Package-Version': version_1.VERSION,
- 'X-Stainless-OS': normalizePlatform(process.platform),
- 'X-Stainless-Arch': normalizeArch(process.arch),
- 'X-Stainless-Runtime': 'node',
- 'X-Stainless-Runtime-Version': process.version,
- };
- }
- const browserInfo = getBrowserInfo();
- if (browserInfo) {
- return {
- 'X-Stainless-Lang': 'js',
- 'X-Stainless-Package-Version': version_1.VERSION,
- 'X-Stainless-OS': 'Unknown',
- 'X-Stainless-Arch': 'unknown',
- 'X-Stainless-Runtime': `browser:${browserInfo.browser}`,
- 'X-Stainless-Runtime-Version': browserInfo.version,
- };
- }
- // TODO add support for Cloudflare workers, etc.
- return {
- 'X-Stainless-Lang': 'js',
- 'X-Stainless-Package-Version': version_1.VERSION,
- 'X-Stainless-OS': 'Unknown',
- 'X-Stainless-Arch': 'unknown',
- 'X-Stainless-Runtime': 'unknown',
- 'X-Stainless-Runtime-Version': 'unknown',
- };
- };
- // Note: modified from https://github.com/JS-DevTools/host-environment/blob/b1ab79ecde37db5d6e163c050e54fe7d287d7c92/src/isomorphic.browser.ts
- function getBrowserInfo() {
- if (typeof navigator === 'undefined' || !navigator) {
- return null;
- }
- // NOTE: The order matters here!
- const browserPatterns = [
- { key: 'edge', pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
- { key: 'ie', pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
- { key: 'ie', pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ },
- { key: 'chrome', pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
- { key: 'firefox', pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
- { key: 'safari', pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ },
- ];
- // Find the FIRST matching browser
- for (const { key, pattern } of browserPatterns) {
- const match = pattern.exec(navigator.userAgent);
- if (match) {
- const major = match[1] || 0;
- const minor = match[2] || 0;
- const patch = match[3] || 0;
- return { browser: key, version: `${major}.${minor}.${patch}` };
- }
- }
- return null;
- }
- const normalizeArch = (arch) => {
- // Node docs:
- // - https://nodejs.org/api/process.html#processarch
- // Deno docs:
- // - https://doc.deno.land/deno/stable/~/Deno.build
- if (arch === 'x32')
- return 'x32';
- if (arch === 'x86_64' || arch === 'x64')
- return 'x64';
- if (arch === 'arm')
- return 'arm';
- if (arch === 'aarch64' || arch === 'arm64')
- return 'arm64';
- if (arch)
- return `other:${arch}`;
- return 'unknown';
- };
- const normalizePlatform = (platform) => {
- // Node platforms:
- // - https://nodejs.org/api/process.html#processplatform
- // Deno platforms:
- // - https://doc.deno.land/deno/stable/~/Deno.build
- // - https://github.com/denoland/deno/issues/14799
- platform = platform.toLowerCase();
- // NOTE: this iOS check is untested and may not work
- // Node does not work natively on IOS, there is a fork at
- // https://github.com/nodejs-mobile/nodejs-mobile
- // however it is unknown at the time of writing how to detect if it is running
- if (platform.includes('ios'))
- return 'iOS';
- if (platform === 'android')
- return 'Android';
- if (platform === 'darwin')
- return 'MacOS';
- if (platform === 'win32')
- return 'Windows';
- if (platform === 'freebsd')
- return 'FreeBSD';
- if (platform === 'openbsd')
- return 'OpenBSD';
- if (platform === 'linux')
- return 'Linux';
- if (platform)
- return `Other:${platform}`;
- return 'Unknown';
- };
- let _platformHeaders;
- const getPlatformHeaders = () => {
- return (_platformHeaders ?? (_platformHeaders = getPlatformProperties()));
- };
- const safeJSON = (text) => {
- try {
- return JSON.parse(text);
- }
- catch (err) {
- return undefined;
- }
- };
- exports.safeJSON = safeJSON;
- // https://url.spec.whatwg.org/#url-scheme-string
- const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;
- const isAbsoluteURL = (url) => {
- return startsWithSchemeRegexp.test(url);
- };
- const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
- exports.sleep = sleep;
- const validatePositiveInteger = (name, n) => {
- if (typeof n !== 'number' || !Number.isInteger(n)) {
- throw new error_1.OpenAIError(`${name} must be an integer`);
- }
- if (n < 0) {
- throw new error_1.OpenAIError(`${name} must be a positive integer`);
- }
- return n;
- };
- const castToError = (err) => {
- if (err instanceof Error)
- return err;
- if (typeof err === 'object' && err !== null) {
- try {
- return new Error(JSON.stringify(err));
- }
- catch { }
- }
- return new Error(err);
- };
- exports.castToError = castToError;
- const ensurePresent = (value) => {
- if (value == null)
- throw new error_1.OpenAIError(`Expected a value to be given but received ${value} instead.`);
- return value;
- };
- exports.ensurePresent = ensurePresent;
- /**
- * Read an environment variable.
- *
- * Trims beginning and trailing whitespace.
- *
- * Will return undefined if the environment variable doesn't exist or cannot be accessed.
- */
- const readEnv = (env) => {
- if (typeof process !== 'undefined') {
- return process.env?.[env]?.trim() ?? undefined;
- }
- if (typeof Deno !== 'undefined') {
- return Deno.env?.get?.(env)?.trim();
- }
- return undefined;
- };
- exports.readEnv = readEnv;
- const coerceInteger = (value) => {
- if (typeof value === 'number')
- return Math.round(value);
- if (typeof value === 'string')
- return parseInt(value, 10);
- throw new error_1.OpenAIError(`Could not coerce ${value} (type: ${typeof value}) into a number`);
- };
- exports.coerceInteger = coerceInteger;
- const coerceFloat = (value) => {
- if (typeof value === 'number')
- return value;
- if (typeof value === 'string')
- return parseFloat(value);
- throw new error_1.OpenAIError(`Could not coerce ${value} (type: ${typeof value}) into a number`);
- };
- exports.coerceFloat = coerceFloat;
- const coerceBoolean = (value) => {
- if (typeof value === 'boolean')
- return value;
- if (typeof value === 'string')
- return value === 'true';
- return Boolean(value);
- };
- exports.coerceBoolean = coerceBoolean;
- const maybeCoerceInteger = (value) => {
- if (value === undefined) {
- return undefined;
- }
- return (0, exports.coerceInteger)(value);
- };
- exports.maybeCoerceInteger = maybeCoerceInteger;
- const maybeCoerceFloat = (value) => {
- if (value === undefined) {
- return undefined;
- }
- return (0, exports.coerceFloat)(value);
- };
- exports.maybeCoerceFloat = maybeCoerceFloat;
- const maybeCoerceBoolean = (value) => {
- if (value === undefined) {
- return undefined;
- }
- return (0, exports.coerceBoolean)(value);
- };
- exports.maybeCoerceBoolean = maybeCoerceBoolean;
- // https://stackoverflow.com/a/34491287
- function isEmptyObj(obj) {
- if (!obj)
- return true;
- for (const _k in obj)
- return false;
- return true;
- }
- exports.isEmptyObj = isEmptyObj;
- // https://eslint.org/docs/latest/rules/no-prototype-builtins
- function hasOwn(obj, key) {
- return Object.prototype.hasOwnProperty.call(obj, key);
- }
- exports.hasOwn = hasOwn;
- /**
- * Copies headers from "newHeaders" onto "targetHeaders",
- * using lower-case for all properties,
- * ignoring any keys with undefined values,
- * and deleting any keys with null values.
- */
- function applyHeadersMut(targetHeaders, newHeaders) {
- for (const k in newHeaders) {
- if (!hasOwn(newHeaders, k))
- continue;
- const lowerKey = k.toLowerCase();
- if (!lowerKey)
- continue;
- const val = newHeaders[k];
- if (val === null) {
- delete targetHeaders[lowerKey];
- }
- else if (val !== undefined) {
- targetHeaders[lowerKey] = val;
- }
- }
- }
- const SENSITIVE_HEADERS = new Set(['authorization', 'api-key']);
- function debug(action, ...args) {
- if (typeof process !== 'undefined' && process?.env?.['DEBUG'] === 'true') {
- const modifiedArgs = args.map((arg) => {
- if (!arg) {
- return arg;
- }
- // Check for sensitive headers in request body 'headers' object
- if (arg['headers']) {
- // clone so we don't mutate
- const modifiedArg = { ...arg, headers: { ...arg['headers'] } };
- for (const header in arg['headers']) {
- if (SENSITIVE_HEADERS.has(header.toLowerCase())) {
- modifiedArg['headers'][header] = 'REDACTED';
- }
- }
- return modifiedArg;
- }
- let modifiedArg = null;
- // Check for sensitive headers in headers object
- for (const header in arg) {
- if (SENSITIVE_HEADERS.has(header.toLowerCase())) {
- // avoid making a copy until we need to
- modifiedArg ?? (modifiedArg = { ...arg });
- modifiedArg[header] = 'REDACTED';
- }
- }
- return modifiedArg ?? arg;
- });
- console.log(`OpenAI:DEBUG:${action}`, ...modifiedArgs);
- }
- }
- exports.debug = debug;
- /**
- * https://stackoverflow.com/a/2117523
- */
- const uuid4 = () => {
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
- const r = (Math.random() * 16) | 0;
- const v = c === 'x' ? r : (r & 0x3) | 0x8;
- return v.toString(16);
- });
- };
- const isRunningInBrowser = () => {
- return (
- // @ts-ignore
- typeof window !== 'undefined' &&
- // @ts-ignore
- typeof window.document !== 'undefined' &&
- // @ts-ignore
- typeof navigator !== 'undefined');
- };
- exports.isRunningInBrowser = isRunningInBrowser;
- const isHeadersProtocol = (headers) => {
- return typeof headers?.get === 'function';
- };
- exports.isHeadersProtocol = isHeadersProtocol;
- const getRequiredHeader = (headers, header) => {
- const foundHeader = (0, exports.getHeader)(headers, header);
- if (foundHeader === undefined) {
- throw new Error(`Could not find ${header} header`);
- }
- return foundHeader;
- };
- exports.getRequiredHeader = getRequiredHeader;
- const getHeader = (headers, header) => {
- const lowerCasedHeader = header.toLowerCase();
- if ((0, exports.isHeadersProtocol)(headers)) {
- // to deal with the case where the header looks like Stainless-Event-Id
- const intercapsHeader = header[0]?.toUpperCase() +
- header.substring(1).replace(/([^\w])(\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());
- for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {
- const value = headers.get(key);
- if (value) {
- return value;
- }
- }
- }
- for (const [key, value] of Object.entries(headers)) {
- if (key.toLowerCase() === lowerCasedHeader) {
- if (Array.isArray(value)) {
- if (value.length <= 1)
- return value[0];
- console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);
- return value[0];
- }
- return value;
- }
- }
- return undefined;
- };
- exports.getHeader = getHeader;
- /**
- * Encodes a string to Base64 format.
- */
- const toBase64 = (str) => {
- if (!str)
- return '';
- if (typeof Buffer !== 'undefined') {
- return Buffer.from(str).toString('base64');
- }
- if (typeof btoa !== 'undefined') {
- return btoa(str);
- }
- throw new error_1.OpenAIError('Cannot generate b64 string; Expected `Buffer` or `btoa` to be defined');
- };
- exports.toBase64 = toBase64;
- /**
- * Converts a Base64 encoded string to a Float32Array.
- * @param base64Str - The Base64 encoded string.
- * @returns An Array of numbers interpreted as Float32 values.
- */
- const toFloat32Array = (base64Str) => {
- if (typeof Buffer !== 'undefined') {
- // for Node.js environment
- const buf = Buffer.from(base64Str, 'base64');
- return Array.from(new Float32Array(buf.buffer, buf.byteOffset, buf.length / Float32Array.BYTES_PER_ELEMENT));
- }
- else {
- // for legacy web platform APIs
- const binaryStr = atob(base64Str);
- const len = binaryStr.length;
- const bytes = new Uint8Array(len);
- for (let i = 0; i < len; i++) {
- bytes[i] = binaryStr.charCodeAt(i);
- }
- return Array.from(new Float32Array(bytes.buffer));
- }
- };
- exports.toFloat32Array = toFloat32Array;
- function isObj(obj) {
- return obj != null && typeof obj === 'object' && !Array.isArray(obj);
- }
- exports.isObj = isObj;
- //# sourceMappingURL=core.js.map
|