From 4ae1207428ded654efde66ecf54ab1e38c54a80f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 15 Feb 2026 04:15:43 +0000 Subject: [PATCH] Validate normalized baseURL cannot be empty Co-authored-by: Eric Allam --- docs/tasks/streams.mdx | 3 ++- packages/ai/CHANGELOG.md | 1 + packages/ai/README.md | 1 + packages/ai/src/chatTransport.test.ts | 11 +++++++++++ packages/ai/src/chatTransport.ts | 8 +++++++- 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/docs/tasks/streams.mdx b/docs/tasks/streams.mdx index eddba511f..8c33a30e2 100644 --- a/docs/tasks/streams.mdx +++ b/docs/tasks/streams.mdx @@ -654,7 +654,8 @@ Subsequent reconnect calls will retry stale inactive-state cleanup until it succ If `onError` is omitted, reconnect still returns `null` and continues without callback reporting. `baseURL` supports optional path prefixes and trailing slashes; both trigger and stream URLs -are normalized consistently, and surrounding whitespace is trimmed before normalization. +are normalized consistently, surrounding whitespace is trimmed before normalization, and +the resulting value must not be empty. For richer TypeScript ergonomics in app code, `@trigger.dev/ai` also exports: diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index b299cce95..24d16d771 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -21,3 +21,4 @@ - Added retry semantics for stale inactive reconnect cleanup on subsequent reconnect attempts. - Added consistent baseURL normalization for trigger and stream endpoints (including path prefixes and trailing slashes). - Added surrounding-whitespace trimming for `baseURL` before endpoint normalization. +- Added explicit validation that `baseURL` is non-empty after normalization. diff --git a/packages/ai/README.md b/packages/ai/README.md index eb034a9e5..96c603174 100644 --- a/packages/ai/README.md +++ b/packages/ai/README.md @@ -160,6 +160,7 @@ both cleanup steps (`set` inactive state and `delete`) even if one of them fails - `baseURL` supports optional path prefixes (for example reverse-proxy mounts). - Trailing slashes are normalized automatically before trigger/stream requests. - Surrounding whitespace is trimmed before normalization. +- `baseURL` must not be empty after trimming/normalization. ## `ai.tool(...)` example diff --git a/packages/ai/src/chatTransport.test.ts b/packages/ai/src/chatTransport.test.ts index 07ac28234..ba28af13b 100644 --- a/packages/ai/src/chatTransport.test.ts +++ b/packages/ai/src/chatTransport.test.ts @@ -609,6 +609,17 @@ describe("TriggerChatTransport", function () { expect(observedStreamPath).toBe("/trimmed-prefix/realtime/v1/streams/run_trimmed_prefix/chat-stream"); }); + it("throws when baseURL is empty after trimming", function () { + expect(function () { + new TriggerChatTransport({ + task: "chat-task", + accessToken: "pk_trigger", + baseURL: " /// ", + stream: "chat-stream", + }); + }).toThrowError("baseURL must not be empty"); + }); + it("combines path prefixes with run and stream URL encoding", async function () { let observedTriggerPath: string | undefined; let observedStreamPath: string | undefined; diff --git a/packages/ai/src/chatTransport.ts b/packages/ai/src/chatTransport.ts index 29debdbda..f934d13c5 100644 --- a/packages/ai/src/chatTransport.ts +++ b/packages/ai/src/chatTransport.ts @@ -460,7 +460,13 @@ function resolvePayloadMapper< } function normalizeBaseUrl(baseURL: string) { - return baseURL.trim().replace(/\/+$/, ""); + const normalizedBaseUrl = baseURL.trim().replace(/\/+$/, ""); + + if (normalizedBaseUrl.length === 0) { + throw new Error("baseURL must not be empty"); + } + + return normalizedBaseUrl; } function createTransportRequest(