Skip to content

Commit 0307ed5

Browse files
committed
address feedback
1 parent 9086c73 commit 0307ed5

File tree

5 files changed

+38
-65
lines changed

5 files changed

+38
-65
lines changed

src/azure.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,8 @@ export class AzureOpenAI extends OpenAI {
109109
}
110110

111111
super({
112-
apiKey,
112+
apiKey: azureADTokenProvider ?? apiKey,
113113
baseURL,
114-
tokenProvider:
115-
!azureADTokenProvider ? undefined : async () => ({ token: await azureADTokenProvider() }),
116114
...opts,
117115
...(dangerouslyAllowBrowser !== undefined ? { dangerouslyAllowBrowser } : {}),
118116
});

src/beta/realtime/websocket.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ export class OpenAIRealtimeWebSocket extends OpenAIRealtimeEmitter {
3939
const dangerouslyAllowBrowser =
4040
props.dangerouslyAllowBrowser ??
4141
(client as any)?._options?.dangerouslyAllowBrowser ??
42-
(client?.apiKey.startsWith('ek_') ? true : null);
43-
42+
(typeof (client as any)?._options?.apiKey === 'string' && client?.apiKey?.startsWith('ek_') ?
43+
true
44+
: null);
4445
if (!dangerouslyAllowBrowser && isRunningInBrowser()) {
4546
throw new OpenAIError(
4647
"It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\n\nYou can avoid this error by creating an ephemeral session token:\nhttps://platform.openai.com/docs/api-reference/realtime-sessions\n",
@@ -49,6 +50,10 @@ export class OpenAIRealtimeWebSocket extends OpenAIRealtimeEmitter {
4950

5051
client ??= new OpenAI({ dangerouslyAllowBrowser });
5152

53+
if (typeof (client as any)?._options?.apiKey !== 'string') {
54+
throw new Error('Call the create method instead to construct the client');
55+
}
56+
5257
this.url = buildRealtimeURL(client, props.model);
5358
props.onURL?.(this.url);
5459

@@ -95,18 +100,18 @@ export class OpenAIRealtimeWebSocket extends OpenAIRealtimeEmitter {
95100
}
96101

97102
static async create(
98-
client: Pick<OpenAI, 'apiKey' | 'baseURL' | '_setToken'>,
103+
client: Pick<OpenAI, 'apiKey' | 'baseURL' | '_setApiKey'>,
99104
props: { model: string; dangerouslyAllowBrowser?: boolean },
100105
): Promise<OpenAIRealtimeWebSocket> {
101-
await client._setToken();
106+
await client._setApiKey();
102107
return new OpenAIRealtimeWebSocket(props, client);
103108
}
104109

105110
static async azure(
106-
client: Pick<AzureOpenAI, '_setToken' | 'apiVersion' | 'apiKey' | 'baseURL' | 'deploymentName'>,
111+
client: Pick<AzureOpenAI, '_setApiKey' | 'apiVersion' | 'apiKey' | 'baseURL' | 'deploymentName'>,
107112
options: { deploymentName?: string; dangerouslyAllowBrowser?: boolean } = {},
108113
): Promise<OpenAIRealtimeWebSocket> {
109-
const isToken = await client._setToken();
114+
const isToken = await client._setApiKey();
110115
function onURL(url: URL) {
111116
if (isToken) {
112117
url.searchParams.set('Authorization', `Bearer ${client.apiKey}`);

src/beta/realtime/ws.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ export class OpenAIRealtimeWS extends OpenAIRealtimeEmitter {
1313
) {
1414
super();
1515
client ??= new OpenAI();
16-
16+
if (typeof (client as any)._options.apiKey !== 'string') {
17+
throw new Error('Call the create method instead to construct the client');
18+
}
1719
this.url = buildRealtimeURL(client, props.model);
1820
this.socket = new WS.WebSocket(this.url, {
1921
...props.options,
@@ -52,15 +54,15 @@ export class OpenAIRealtimeWS extends OpenAIRealtimeEmitter {
5254
}
5355

5456
static async create(
55-
client: Pick<OpenAI, 'apiKey' | 'baseURL' | '_setToken'>,
57+
client: Pick<OpenAI, 'apiKey' | 'baseURL' | '_setApiKey'>,
5658
props: { model: string; options?: WS.ClientOptions | undefined },
5759
): Promise<OpenAIRealtimeWS> {
58-
await client._setToken();
60+
await client._setApiKey();
5961
return new OpenAIRealtimeWS(props, client);
6062
}
6163

6264
static async azure(
63-
client: Pick<AzureOpenAI, '_setToken' | 'apiVersion' | 'apiKey' | 'baseURL' | 'deploymentName'>,
65+
client: Pick<AzureOpenAI, '_setApiKey' | 'apiVersion' | 'apiKey' | 'baseURL' | 'deploymentName'>,
6466
options: { deploymentName?: string; options?: WS.ClientOptions | undefined } = {},
6567
): Promise<OpenAIRealtimeWS> {
6668
const deploymentName = options.deploymentName ?? client.deploymentName;
@@ -90,8 +92,8 @@ export class OpenAIRealtimeWS extends OpenAIRealtimeEmitter {
9092
}
9193
}
9294

93-
async function getAzureHeaders(client: Pick<AzureOpenAI, '_setToken' | 'apiKey'>) {
94-
const isToken = await client._setToken();
95+
async function getAzureHeaders(client: Pick<AzureOpenAI, '_setApiKey' | 'apiKey'>) {
96+
const isToken = await client._setApiKey();
9597
if (isToken) {
9698
return { Authorization: `Bearer ${isToken}` };
9799
} else {

src/client.ts

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -206,20 +206,13 @@ import {
206206
} from './internal/utils/log';
207207
import { isEmptyObj } from './internal/utils/values';
208208

209-
export interface AccessToken {
210-
token: string;
211-
}
212-
export type TokenProvider = () => Promise<AccessToken>;
209+
export type ApiKeySetter = () => Promise<string>;
213210

214211
export interface ClientOptions {
215212
/**
216213
* Defaults to process.env['OPENAI_API_KEY'].
217214
*/
218-
apiKey?: string | undefined;
219-
/**
220-
* A function that returns a token to use for authentication.
221-
*/
222-
tokenProvider?: TokenProvider | undefined;
215+
apiKey?: string | ApiKeySetter | undefined;
223216
/**
224217
* Defaults to process.env['OPENAI_ORG_ID'].
225218
*/
@@ -330,7 +323,6 @@ export class OpenAI {
330323
#encoder: Opts.RequestEncoder;
331324
protected idempotencyHeader?: string;
332325
private _options: ClientOptions;
333-
private _tokenProvider: TokenProvider | undefined;
334326

335327
/**
336328
* API Client for interfacing with the OpenAI API.
@@ -354,18 +346,11 @@ export class OpenAI {
354346
organization = readEnv('OPENAI_ORG_ID') ?? null,
355347
project = readEnv('OPENAI_PROJECT_ID') ?? null,
356348
webhookSecret = readEnv('OPENAI_WEBHOOK_SECRET') ?? null,
357-
tokenProvider,
358349
...opts
359350
}: ClientOptions = {}) {
360-
if (apiKey === undefined && !tokenProvider) {
361-
throw new Errors.OpenAIError(
362-
'Missing credentials. Please pass one of `apiKey` and `tokenProvider`, or set the `OPENAI_API_KEY` environment variable.',
363-
);
364-
}
365-
366-
if (tokenProvider && apiKey) {
351+
if (apiKey === undefined) {
367352
throw new Errors.OpenAIError(
368-
'The `apiKey` and `tokenProvider` arguments are mutually exclusive; only one can be passed at a time.',
353+
'Missing credentials. Please pass an `apiKey`, or set the `OPENAI_API_KEY` environment variable.',
369354
);
370355
}
371356

@@ -374,7 +359,6 @@ export class OpenAI {
374359
organization,
375360
project,
376361
webhookSecret,
377-
tokenProvider,
378362
...opts,
379363
baseURL: baseURL || `https://api.openai.com/v1`,
380364
};
@@ -402,8 +386,7 @@ export class OpenAI {
402386

403387
this._options = options;
404388

405-
this.apiKey = apiKey ?? 'Missing Key';
406-
this._tokenProvider = tokenProvider;
389+
this.apiKey = typeof apiKey === 'string' ? apiKey : 'Missing Key';
407390
this.organization = organization;
408391
this.project = project;
409392
this.webhookSecret = webhookSecret;
@@ -423,7 +406,6 @@ export class OpenAI {
423406
fetch: this.fetch,
424407
fetchOptions: this.fetchOptions,
425408
apiKey: this.apiKey,
426-
tokenProvider: this._tokenProvider,
427409
organization: this.organization,
428410
project: this.project,
429411
webhookSecret: this.webhookSecret,
@@ -472,23 +454,24 @@ export class OpenAI {
472454
return Errors.APIError.generate(status, error, message, headers);
473455
}
474456

475-
async _setToken(): Promise<boolean> {
476-
if (typeof this._tokenProvider === 'function') {
457+
async _setApiKey(): Promise<boolean> {
458+
const apiKey = this._options.apiKey;
459+
if (typeof apiKey === 'function') {
477460
try {
478-
const token = await this._tokenProvider();
479-
if (!token || typeof token.token !== 'string') {
461+
const token = await apiKey();
462+
if (!token || typeof token !== 'string') {
480463
throw new Errors.OpenAIError(
481-
`Expected 'tokenProvider' argument to return a string but it returned ${token}`,
464+
`Expected 'apiKey' function argument to return a string but it returned ${token}`,
482465
);
483466
}
484-
this.apiKey = token.token;
467+
this.apiKey = token;
485468
return true;
486469
} catch (err: any) {
487470
if (err instanceof Errors.OpenAIError) {
488471
throw err;
489472
}
490473
throw new Errors.OpenAIError(
491-
`Failed to get token from 'tokenProvider' function: ${err.message}`,
474+
`Failed to get token from 'apiKey' function: ${err.message}`,
492475
// @ts-ignore
493476
{ cause: err },
494477
);
@@ -524,7 +507,7 @@ export class OpenAI {
524507
* Used as a callback for mutating the given `FinalRequestOptions` object.
525508
*/
526509
protected async prepareOptions(options: FinalRequestOptions): Promise<void> {
527-
await this._setToken();
510+
await this._setApiKey();
528511
}
529512

530513
/**

tests/index.test.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ describe('retries', () => {
736736
};
737737
const client = new OpenAI({
738738
baseURL: 'http://localhost:5000/',
739-
tokenProvider: async () => ({ token: 'my token' }),
739+
apiKey: async () => 'my token',
740740
fetch: testFetch,
741741
});
742742
expect(
@@ -763,12 +763,12 @@ describe('retries', () => {
763763
});
764764
};
765765
let counter = 0;
766-
async function tokenProvider() {
767-
return { token: `token-${counter++}` };
766+
async function apiKey() {
767+
return `token-${counter++}`;
768768
}
769769
const client = new OpenAI({
770770
baseURL: 'http://localhost:5000/',
771-
tokenProvider,
771+
apiKey,
772772
fetch: testFetch,
773773
});
774774
expect(
@@ -783,21 +783,6 @@ describe('retries', () => {
783783
).toEqual('Bearer token-1');
784784
});
785785

786-
test('mutual exclusive', () => {
787-
try {
788-
new OpenAI({
789-
baseURL: 'http://localhost:5000/',
790-
tokenProvider: async () => ({ token: 'my token' }),
791-
apiKey: 'my api key',
792-
});
793-
} catch (error: any) {
794-
expect(error).toBeInstanceOf(Error);
795-
expect(error.message).toEqual(
796-
'The `apiKey` and `tokenProvider` arguments are mutually exclusive; only one can be passed at a time.',
797-
);
798-
}
799-
});
800-
801786
test('at least one', () => {
802787
try {
803788
new OpenAI({

0 commit comments

Comments
 (0)