mirror of
https://github.com/langchain-ai/langgraphjs.git
synced 2026-07-23 09:35:22 -04:00
feat(js-sdk): skip auto loading api key when set to null on sdk client create (#1793)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@langchain/langgraph-sdk": patch
|
||||
---
|
||||
|
||||
Adding support to skip auto loading api key when set to null on sdk client create
|
||||
+17
-4
@@ -122,19 +122,26 @@ function mergeHeaders(
|
||||
/**
|
||||
* Get the API key from the environment.
|
||||
* Precedence:
|
||||
* 1. explicit argument
|
||||
* 1. explicit argument (if string)
|
||||
* 2. LANGGRAPH_API_KEY
|
||||
* 3. LANGSMITH_API_KEY
|
||||
* 4. LANGCHAIN_API_KEY
|
||||
*
|
||||
* @param apiKey - Optional API key provided as an argument
|
||||
* @param apiKey - API key provided as an argument. If null, skips environment lookup. If undefined, tries environment.
|
||||
* @returns The API key if found, otherwise undefined
|
||||
*/
|
||||
export function getApiKey(apiKey?: string): string | undefined {
|
||||
export function getApiKey(apiKey?: string | null): string | undefined {
|
||||
// If explicitly set to null, skip auto-loading
|
||||
if (apiKey === null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If a string value is provided, use it
|
||||
if (apiKey) {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
// If undefined, try to load from environment
|
||||
const prefixes = ["LANGGRAPH", "LANGSMITH", "LANGCHAIN"];
|
||||
|
||||
for (const prefix of prefixes) {
|
||||
@@ -173,7 +180,13 @@ export type RequestHook = (
|
||||
|
||||
export interface ClientConfig {
|
||||
apiUrl?: string;
|
||||
apiKey?: string;
|
||||
/**
|
||||
* API key for authentication.
|
||||
* - If a string is provided, that key will be used
|
||||
* - If undefined (default), the key will be auto-loaded from environment variables (LANGGRAPH_API_KEY, LANGSMITH_API_KEY, or LANGCHAIN_API_KEY)
|
||||
* - If null, no API key will be set (skips auto-loading)
|
||||
*/
|
||||
apiKey?: string | null;
|
||||
callerOptions?: AsyncCallerParams;
|
||||
timeoutMs?: number;
|
||||
defaultHeaders?: Record<string, HeaderValue>;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
||||
import { Client } from "../client.js";
|
||||
import { overrideFetchImplementation } from "../singletons/fetch.js";
|
||||
import * as envUtils from "../utils/env.js";
|
||||
|
||||
describe.each([["global"], ["mocked"]])(
|
||||
"Client uses %s fetch",
|
||||
@@ -197,5 +198,92 @@ describe.each([["global"], ["mocked"]])(
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("API key auto-load", () => {
|
||||
it("should auto-load API key from environment when apiKey is undefined", async () => {
|
||||
const getEnvSpy = vi
|
||||
.spyOn(envUtils, "getEnvironmentVariable")
|
||||
.mockImplementation((name: string) => {
|
||||
if (name === "LANGGRAPH_API_KEY") return "env-api-key";
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const client = new Client();
|
||||
await (client.threads as any).fetch("/test");
|
||||
|
||||
expect(expectedFetchMock).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.any(URL),
|
||||
expect.objectContaining({
|
||||
headers: expect.objectContaining({
|
||||
"x-api-key": "env-api-key",
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
const client2 = new Client({ apiKey: undefined });
|
||||
await (client2.threads as any).fetch("/test");
|
||||
|
||||
expect(expectedFetchMock).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.any(URL),
|
||||
expect.objectContaining({
|
||||
headers: expect.objectContaining({
|
||||
"x-api-key": "env-api-key",
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
getEnvSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("should skip API key auto-load when apiKey is null", async () => {
|
||||
const getEnvSpy = vi
|
||||
.spyOn(envUtils, "getEnvironmentVariable")
|
||||
.mockImplementation((name: string) => {
|
||||
if (name === "LANGGRAPH_API_KEY") return "env-api-key";
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const client = new Client({ apiKey: null });
|
||||
await (client.threads as any).fetch("/test");
|
||||
|
||||
expect(expectedFetchMock).toHaveBeenCalledWith(
|
||||
expect.any(URL),
|
||||
expect.objectContaining({
|
||||
headers: expect.not.objectContaining({
|
||||
"x-api-key": expect.anything(),
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
getEnvSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("should use explicit API key when provided as a string", async () => {
|
||||
const getEnvSpy = vi
|
||||
.spyOn(envUtils, "getEnvironmentVariable")
|
||||
.mockImplementation((name: string) => {
|
||||
if (name === "LANGGRAPH_API_KEY") return "env-api-key";
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const client = new Client({
|
||||
apiKey: "explicit-api-key",
|
||||
});
|
||||
await (client.threads as any).fetch("/test");
|
||||
|
||||
expect(expectedFetchMock).toHaveBeenCalledWith(
|
||||
expect.any(URL),
|
||||
expect.objectContaining({
|
||||
headers: expect.objectContaining({
|
||||
"x-api-key": "explicit-api-key",
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
getEnvSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user