diff --git a/src/openai/client.js b/src/openai/client.js index f207005..cbc0ab0 100644 --- a/src/openai/client.js +++ b/src/openai/client.js @@ -1 +1,18 @@ // OpenAI API client wrapper. + +import OpenAI from "openai"; + +/** + * Create an OpenAI SDK client from the loaded config. + * @param {object} config - Config object from loadConfig() + * @param {string} config.openaiApiKey - Required. The OpenAI API key. + * @returns {OpenAI} The configured OpenAI SDK client instance. + */ +export function createOpenAIClient(config) { + if (!config?.openaiApiKey) { + throw new Error("Missing config.openaiApiKey."); + } + return new OpenAI({ + apiKey: config.openaiApiKey, + }); +} diff --git a/test/openai/client.test.js b/test/openai/client.test.js new file mode 100644 index 0000000..cf03bcc --- /dev/null +++ b/test/openai/client.test.js @@ -0,0 +1,39 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; + +const MockClient = vi.fn(function (opts) { + this.apiKey = opts?.apiKey; +}); + +// Mock the OpenAI SDK — Vitest hoists vi.mock automatically. +vi.mock("openai", () => ({ default: MockClient })); + +const { createOpenAIClient } = await import("../../src/openai/client.js"); + +describe("createOpenAIClient", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("creates OpenAI client with supplied apiKey", () => { + const config = { openaiApiKey: "sk-test-key" }; + const client = createOpenAIClient(config); + + expect(MockClient).toHaveBeenCalledTimes(1); + expect(MockClient).toHaveBeenCalledWith({ apiKey: "sk-test-key" }); + expect(client.apiKey).toBe("sk-test-key"); + }); + + it("throws when openaiApiKey is missing", () => { + const config = {}; + + expect(() => createOpenAIClient(config)).toThrow("Missing config.openaiApiKey."); + expect(MockClient).not.toHaveBeenCalled(); + }); + + it("throws when openaiApiKey is empty string", () => { + const config = { openaiApiKey: "" }; + + expect(() => createOpenAIClient(config)).toThrow("Missing config.openaiApiKey."); + expect(MockClient).not.toHaveBeenCalled(); + }); +});