Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "5.3.0"
".": "5.4.0"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 111
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-3ae9c18dd7ccfc3ac5206f24394665f563a19015cfa8847b2801a2694d012abc.yml
openapi_spec_hash: 48175b03b58805cd5c80793c66fd54e5
config_hash: 4caff63b74a41f71006987db702f2918
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9e41d2d5471d2c28bff0d616f4476f5b0e6c541ef4cb51bdaaef5fdf5e13c8b2.yml
openapi_spec_hash: 86f765e18d00e32cf2ce9db7ab84d946
config_hash: fd2af1d5eff0995bb7dc02ac9a34851d
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Changelog

## 5.4.0 (2025-06-16)

Full Changelog: [v5.3.0...v5.4.0](https://github.com/openai/openai-node/compare/v5.3.0...v5.4.0)

### Features

* **api:** add reusable prompt IDs ([c720bb3](https://github.com/openai/openai-node/commit/c720bb3fb909cdef1cc679df38357f046d3d2756))
* **client:** add support for endpoint-specific base URLs ([05f558b](https://github.com/openai/openai-node/commit/05f558bcdd362ae56000fe515a24593363d59e83))


### Bug Fixes

* publish script — handle NPM errors correctly ([a803cce](https://github.com/openai/openai-node/commit/a803cce6d44116eaba34f2bd7cb0f5d8f5c72be8))


### Chores

* **client:** refactor imports ([9eb4470](https://github.com/openai/openai-node/commit/9eb44703432d7e22290564013f8e1798c82918a3))
* **internal:** add pure annotations, make base APIResource abstract ([418eb02](https://github.com/openai/openai-node/commit/418eb02e3ebe3ef58d851405f9eb5cae275194b4))

## 5.3.0 (2025-06-10)

Full Changelog: [v5.2.0...v5.3.0](https://github.com/openai/openai-node/compare/v5.2.0...v5.3.0)
Expand Down
1 change: 1 addition & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ Types:
- <code><a href="./src/resources/responses/responses.ts">ResponseOutputRefusal</a></code>
- <code><a href="./src/resources/responses/responses.ts">ResponseOutputText</a></code>
- <code><a href="./src/resources/responses/responses.ts">ResponseOutputTextAnnotationAddedEvent</a></code>
- <code><a href="./src/resources/responses/responses.ts">ResponsePrompt</a></code>
- <code><a href="./src/resources/responses/responses.ts">ResponseQueuedEvent</a></code>
- <code><a href="./src/resources/responses/responses.ts">ResponseReasoningDeltaEvent</a></code>
- <code><a href="./src/resources/responses/responses.ts">ResponseReasoningDoneEvent</a></code>
Expand Down
34 changes: 27 additions & 7 deletions bin/publish-npm
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,35 @@ npm config set '//registry.npmjs.org/:_authToken' "$NPM_TOKEN"
yarn build
cd dist

# Get package name and version from package.json
PACKAGE_NAME="$(jq -r -e '.name' ./package.json)"
VERSION="$(jq -r -e '.version' ./package.json)"

# Get latest version from npm
#
# If the package doesn't exist, yarn will return
# {"type":"error","data":"Received invalid response from npm."}
# where .data.version doesn't exist so LAST_VERSION will be an empty string.
LAST_VERSION="$(yarn info --json 2> /dev/null | jq -r '.data.version')"

# Get current version from package.json
VERSION="$(node -p "require('./package.json').version")"
# If the package doesn't exist, npm will return:
# {
# "error": {
# "code": "E404",
# "summary": "Unpublished on 2025-06-05T09:54:53.528Z",
# "detail": "'the_package' is not in this registry..."
# }
# }
NPM_INFO="$(npm view "$PACKAGE_NAME" version --json 2>/dev/null || true)"

# Check if we got an E404 error
if echo "$NPM_INFO" | jq -e '.error.code == "E404"' > /dev/null 2>&1; then
# Package doesn't exist yet, no last version
LAST_VERSION=""
elif echo "$NPM_INFO" | jq -e '.error' > /dev/null 2>&1; then
# Report other errors
echo "ERROR: npm returned unexpected data:"
echo "$NPM_INFO"
exit 1
else
# Success - get the version
LAST_VERSION=$(echo "$NPM_INFO" | jq -r '.') # strip quotes
fi

# Check if current version is pre-release (e.g. alpha / beta / rc)
CURRENT_IS_PRERELEASE=false
Expand Down
2 changes: 1 addition & 1 deletion jsr.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openai/openai",
"version": "5.3.0",
"version": "5.4.0",
"exports": {
".": "./index.ts",
"./helpers/zod": "./helpers/zod.ts",
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "openai",
"version": "5.3.0",
"version": "5.4.0",
"description": "The official TypeScript library for the OpenAI API",
"author": "OpenAI <[email protected]>",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -45,7 +45,7 @@
"publint": "^0.2.12",
"ts-jest": "^29.1.0",
"ts-node": "^10.5.0",
"tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz",
"tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz",
"tsconfig-paths": "^4.0.0",
"typescript": "5.8.3",
"ws": "^8.18.0",
Expand Down
2 changes: 1 addition & 1 deletion scripts/build
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fi
node scripts/utils/make-dist-package-json.cjs > dist/package.json

# build to .js/.mjs/.d.ts files
npm exec tsc-multi
./node_modules/.bin/tsc-multi
# we need to patch index.js so that `new module.exports()` works for cjs backwards
# compat. No way to get that from index.ts because it would cause compile errors
# when building .mjs
Expand Down
41 changes: 29 additions & 12 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import type { HTTPMethod, PromiseOrValue, MergedRequestInit, FinalizedRequestIni
import { uuid4 } from './internal/utils/uuid';
import { validatePositiveInteger, isAbsoluteURL, safeJSON } from './internal/utils/values';
import { sleep } from './internal/utils/sleep';
import { type Logger, type LogLevel, parseLogLevel } from './internal/utils/log';
export type { Logger, LogLevel } from './internal/utils/log';
import { castToError, isAbortError } from './internal/errors';
import type { APIResponseProps } from './internal/parse';
Expand All @@ -20,10 +19,6 @@ import { AbstractPage, type CursorPageParams, CursorPageResponse, PageResponse }
import * as Uploads from './core/uploads';
import * as API from './resources/index';
import { APIPromise } from './core/api-promise';
import { type Fetch } from './internal/builtin-types';
import { isRunningInBrowser } from './internal/detect-platform';
import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers';
import { FinalRequestOptions, RequestOptions } from './internal/request-options';
import {
Batch,
BatchCreateParams,
Expand Down Expand Up @@ -79,9 +74,6 @@ import {
ModerationTextInput,
Moderations,
} from './resources/moderations';
import { readEnv } from './internal/utils/env';
import { formatRequestDetails, loggerFor } from './internal/utils/log';
import { isEmptyObj } from './internal/utils/values';
import { Audio, AudioModel, AudioResponseFormat } from './resources/audio/audio';
import { Beta } from './resources/beta/beta';
import { Chat } from './resources/chat/chat';
Expand Down Expand Up @@ -174,6 +166,19 @@ import {
ChatCompletionUserMessageParam,
ChatCompletionsPage,
} from './resources/chat/completions/completions';
import { type Fetch } from './internal/builtin-types';
import { isRunningInBrowser } from './internal/detect-platform';
import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers';
import { FinalRequestOptions, RequestOptions } from './internal/request-options';
import { readEnv } from './internal/utils/env';
import {
type LogLevel,
type Logger,
formatRequestDetails,
loggerFor,
parseLogLevel,
} from './internal/utils/log';
import { isEmptyObj } from './internal/utils/values';

export interface ClientOptions {
/**
Expand Down Expand Up @@ -367,6 +372,13 @@ export class OpenAI {
});
}

/**
* Check whether the base URL is set to its default.
*/
#baseURLOverridden(): boolean {
return this.baseURL !== 'https://api.openai.com/v1';
}

protected defaultQuery(): Record<string, string | undefined> | undefined {
return this._options.defaultQuery;
}
Expand Down Expand Up @@ -400,11 +412,16 @@ export class OpenAI {
return Errors.APIError.generate(status, error, message, headers);
}

buildURL(path: string, query: Record<string, unknown> | null | undefined): string {
buildURL(
path: string,
query: Record<string, unknown> | null | undefined,
defaultBaseURL?: string | undefined,
): string {
const baseURL = (!this.#baseURLOverridden() && defaultBaseURL) || this.baseURL;
const url =
isAbsoluteURL(path) ?
new URL(path)
: new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
: new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));

const defaultQuery = this.defaultQuery();
if (!isEmptyObj(defaultQuery)) {
Expand Down Expand Up @@ -768,9 +785,9 @@ export class OpenAI {
{ retryCount = 0 }: { retryCount?: number } = {},
): { req: FinalizedRequestInit; url: string; timeout: number } {
const options = { ...inputOptions };
const { method, path, query } = options;
const { method, path, query, defaultBaseURL } = options;

const url = this.buildURL(path!, query as Record<string, unknown>);
const url = this.buildURL(path!, query as Record<string, unknown>, defaultBaseURL);
if ('timeout' in options) validatePositiveInteger('timeout', options.timeout);
options.timeout = options.timeout ?? this.timeout;
const { bodyHeaders, body } = this.buildBody({ options });
Expand Down
2 changes: 1 addition & 1 deletion src/core/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import type { OpenAI } from '../client';

export class APIResource {
export abstract class APIResource {
protected _client: OpenAI;

constructor(client: OpenAI) {
Expand Down
10 changes: 5 additions & 5 deletions src/internal/headers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

import { isReadonlyArray } from './utils/values';

type HeaderValue = string | undefined | null;
export type HeadersLike =
| Headers
Expand All @@ -9,7 +11,7 @@ export type HeadersLike =
| null
| NullableHeaders;

const brand_privateNullableHeaders = Symbol('brand.privateNullableHeaders');
const brand_privateNullableHeaders = /* @__PURE__ */ Symbol('brand.privateNullableHeaders');

/**
* @internal
Expand All @@ -25,8 +27,6 @@ export type NullableHeaders = {
nulls: Set<string>;
};

const isArray = Array.isArray as (val: unknown) => val is readonly unknown[];

function* iterateHeaders(headers: HeadersLike): IterableIterator<readonly [string, string | null]> {
if (!headers) return;

Expand All @@ -43,7 +43,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator<readonly [strin
let iter: Iterable<readonly (HeaderValue | readonly HeaderValue[])[]>;
if (headers instanceof Headers) {
iter = headers.entries();
} else if (isArray(headers)) {
} else if (isReadonlyArray(headers)) {
iter = headers;
} else {
shouldClear = true;
Expand All @@ -52,7 +52,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator<readonly [strin
for (let row of iter) {
const name = row[0];
if (typeof name !== 'string') throw new TypeError('expected header name to be a string');
const values = isArray(row[1]) ? row[1] : [row[1]];
const values = isReadonlyArray(row[1]) ? row[1] : [row[1]];
let didClear = false;
for (const value of values) {
if (value === undefined) continue;
Expand Down
3 changes: 2 additions & 1 deletion src/internal/qs/formats.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { Format } from './types';

export const default_format: Format = 'RFC3986';
export const default_formatter = (v: PropertyKey) => String(v);
export const formatters: Record<Format, (str: PropertyKey) => string> = {
RFC1738: (v: PropertyKey) => String(v).replace(/%20/g, '+'),
RFC3986: (v: PropertyKey) => String(v),
RFC3986: default_formatter,
};
export const RFC1738 = 'RFC1738';
export const RFC3986 = 'RFC3986';
Loading