Reject internal whitespace in normalized baseURL values
Co-authored-by: Eric Allam <eric@trigger.dev>
This commit is contained in:
@@ -9,5 +9,6 @@ Add a new `@trigger.dev/ai` package with:
|
||||
- rich default task payloads (`chatId`, trigger metadata, messages, request context) with optional payload mapping
|
||||
- reconnect-aware stream handling on top of Trigger.dev Realtime Streams v2
|
||||
- strict `baseURL` normalization/validation (trimming, path-safe slash handling, absolute `http(s)` URLs only, no query/hash/credentials)
|
||||
- rejection of internal whitespace characters in normalized `baseURL` values
|
||||
- deterministic baseURL validation error ordering for multi-issue inputs (protocol → query/hash → credentials)
|
||||
- explicit default `baseURL` behavior (`https://api.trigger.dev`) and case-insensitive `HTTP(S)` protocol acceptance
|
||||
|
||||
@@ -671,11 +671,13 @@ Examples:
|
||||
- ❌ `https://user:pass@api.trigger.dev`
|
||||
- ❌ `ftp://api.trigger.dev`
|
||||
- ❌ `ws://api.trigger.dev` / `wss://api.trigger.dev`
|
||||
- ❌ `https://api.trigger.dev/\ninternal`
|
||||
|
||||
Validation errors use these exact messages:
|
||||
|
||||
- `baseURL must not be empty`
|
||||
- `baseURL must be a valid absolute URL`
|
||||
- `baseURL must not contain internal whitespace characters`
|
||||
- `baseURL must use http or https protocol`
|
||||
- `baseURL must not include query parameters or hash fragments`
|
||||
- `baseURL must not include username or password credentials`
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
- Added explicit validation that `baseURL` uses `http` or `https`.
|
||||
- Added explicit validation that `baseURL` excludes query parameters and hash fragments.
|
||||
- Added explicit validation that `baseURL` excludes username/password credentials.
|
||||
- Added explicit validation that `baseURL` excludes internal whitespace characters.
|
||||
- Documented that `HTTP://` and `HTTPS://` are accepted (case-insensitive protocol matching).
|
||||
- Added deterministic validation ordering for multi-issue baseURL values
|
||||
(protocol → query/hash → credentials).
|
||||
|
||||
@@ -178,11 +178,13 @@ Examples:
|
||||
- ❌ `https://user:pass@api.trigger.dev` (credentials)
|
||||
- ❌ `ftp://api.trigger.dev` (non-http protocol)
|
||||
- ❌ `ws://api.trigger.dev` / `wss://api.trigger.dev` (websocket protocols are rejected)
|
||||
- ❌ `https://api.trigger.dev/\ninternal` (internal whitespace characters)
|
||||
|
||||
Validation errors use these exact messages:
|
||||
|
||||
- `baseURL must not be empty`
|
||||
- `baseURL must be a valid absolute URL`
|
||||
- `baseURL must not contain internal whitespace characters`
|
||||
- `baseURL must use http or https protocol`
|
||||
- `baseURL must not include query parameters or hash fragments`
|
||||
- `baseURL must not include username or password credentials`
|
||||
|
||||
@@ -720,6 +720,17 @@ describe("TriggerChatTransport", function () {
|
||||
}).toThrowError("baseURL must be a valid absolute URL");
|
||||
});
|
||||
|
||||
it("throws when baseURL contains internal whitespace characters", function () {
|
||||
expect(function () {
|
||||
new TriggerChatTransport({
|
||||
task: "chat-task",
|
||||
accessToken: "pk_trigger",
|
||||
baseURL: "https://api.trigger.dev/\ninternal",
|
||||
stream: "chat-stream",
|
||||
});
|
||||
}).toThrowError("baseURL must not contain internal whitespace characters");
|
||||
});
|
||||
|
||||
it("throws when baseURL is a relative path", function () {
|
||||
expect(function () {
|
||||
new TriggerChatTransport({
|
||||
@@ -3250,6 +3261,17 @@ describe("TriggerChatTransport", function () {
|
||||
}).toThrowError("baseURL must be a valid absolute URL");
|
||||
});
|
||||
|
||||
it("throws from factory when baseURL contains internal whitespace characters", function () {
|
||||
expect(function () {
|
||||
createTriggerChatTransport({
|
||||
task: "chat-task",
|
||||
accessToken: "pk_trigger",
|
||||
baseURL: "https://api.trigger.dev/\ninternal",
|
||||
stream: "chat-stream",
|
||||
});
|
||||
}).toThrowError("baseURL must not contain internal whitespace characters");
|
||||
});
|
||||
|
||||
it("throws from factory when baseURL protocol is not http or https", function () {
|
||||
expect(function () {
|
||||
createTriggerChatTransport({
|
||||
|
||||
@@ -451,6 +451,7 @@ export function createTriggerChatTransport<
|
||||
const BASE_URL_VALIDATION_ERRORS = {
|
||||
empty: "baseURL must not be empty",
|
||||
invalidAbsoluteUrl: "baseURL must be a valid absolute URL",
|
||||
containsWhitespace: "baseURL must not contain internal whitespace characters",
|
||||
invalidProtocol: "baseURL must use http or https protocol",
|
||||
queryOrHash: "baseURL must not include query parameters or hash fragments",
|
||||
credentials: "baseURL must not include username or password credentials",
|
||||
@@ -474,6 +475,8 @@ function normalizeBaseUrl(baseURL: string) {
|
||||
throw new Error(BASE_URL_VALIDATION_ERRORS.empty);
|
||||
}
|
||||
|
||||
assertBaseUrlHasNoInternalWhitespace(normalizedBaseUrl);
|
||||
|
||||
let parsedBaseUrl: URL;
|
||||
try {
|
||||
parsedBaseUrl = new URL(normalizedBaseUrl);
|
||||
@@ -488,6 +491,12 @@ function normalizeBaseUrl(baseURL: string) {
|
||||
return normalizedBaseUrl;
|
||||
}
|
||||
|
||||
function assertBaseUrlHasNoInternalWhitespace(baseUrl: string) {
|
||||
if (/\s/.test(baseUrl)) {
|
||||
throw new Error(BASE_URL_VALIDATION_ERRORS.containsWhitespace);
|
||||
}
|
||||
}
|
||||
|
||||
function assertValidBaseUrlProtocol(parsedBaseUrl: URL) {
|
||||
if (
|
||||
parsedBaseUrl.protocol !== "http:" &&
|
||||
|
||||
Reference in New Issue
Block a user