Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions credentials/BrowserbaseApi.credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ export class BrowserbaseApi implements ICredentialType {
required: true,
description: 'Your Browserbase API key',
},
{
displayName: 'Base URL',
name: 'baseUrl',
type: 'hidden',
default: 'https://api.browserbase.com',
},
{
displayName: 'Stagehand Base URL',
name: 'stagehandBaseUrl',
type: 'hidden',
default: 'https://api.stagehand.browserbase.com',
},
{
displayName: 'Browserbase Project ID (Deprecated)',
name: 'browserbaseProjectId',
Expand Down
40 changes: 28 additions & 12 deletions nodes/Browserbase/Browserbase.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ function normalizeUrl(url: string): string {
return `https://${url}`;
}

function normalizeBaseUrl(url: string): string {
return url.trim().replace(/\/+$/, '');
}

function getSessionId(response: Record<string, unknown>): string | undefined {
const data = response.data as Record<string, unknown> | undefined;
return (data?.sessionId ?? response.sessionId ?? response.id) as string | undefined;
Expand Down Expand Up @@ -790,7 +794,7 @@ export class Browserbase implements INodeType {
name: 'browserbase',
icon: 'file:../../icons/browserbase.svg',
group: ['transform'],
version: 2,
version: [2, 2.1],
subtitle:
'={{$parameter["resource"] === "agent" ? $parameter["operation"] + ": " + $parameter["mode"] : $parameter["operation"]}}',
description: 'Browser automation, web search, and page fetches with Browserbase.',
Expand Down Expand Up @@ -818,13 +822,14 @@ export class Browserbase implements INodeType {
): Promise<INodeCredentialTestResult> {
try {
const headers = getHeaders(credential.data!);
const baseUrl = normalizeBaseUrl((credential.data?.baseUrl as string) ?? API_BASE_URL);
const httpRequest = this.helpers['request' as keyof typeof this.helpers] as (
opts: object,
) => Promise<Record<string, unknown>>;

await httpRequest({
method: 'POST',
uri: `${API_BASE_URL}/v1/fetch`,
uri: `${baseUrl}/v1/fetch`,
headers,
body: { url: 'https://browserbase.com/' },
json: true,
Expand Down Expand Up @@ -874,14 +879,15 @@ export class Browserbase implements INodeType {
executeFunctions: IExecuteFunctions,
itemIndex: number,
headers: BrowserbaseHeaders,
baseUrl: string,
): Promise<INodeExecutionData> {
const query = executeFunctions.getNodeParameter('query', itemIndex) as string;
const numResults = executeFunctions.getNodeParameter('numResults', itemIndex) as number;

const response = await this.apiCall(
executeFunctions,
'POST',
API_BASE_URL,
baseUrl,
'/v1/search',
headers,
{
Expand All @@ -907,6 +913,7 @@ export class Browserbase implements INodeType {
executeFunctions: IExecuteFunctions,
itemIndex: number,
headers: BrowserbaseHeaders,
baseUrl: string,
): Promise<INodeExecutionData> {
const url = normalizeUrl(executeFunctions.getNodeParameter('fetchUrl', itemIndex) as string);
const fetchOptions = executeFunctions.getNodeParameter('fetchOptions', itemIndex, {}) as {
Expand All @@ -918,7 +925,7 @@ export class Browserbase implements INodeType {
const response = await this.apiCall(
executeFunctions,
'POST',
API_BASE_URL,
baseUrl,
'/v1/fetch',
headers,
{
Expand Down Expand Up @@ -946,6 +953,7 @@ export class Browserbase implements INodeType {
executeFunctions: IExecuteFunctions,
itemIndex: number,
headers: BrowserbaseHeaders,
baseUrl: string,
): Promise<INodeExecutionData> {
let url = executeFunctions.getNodeParameter('url', itemIndex) as string;
url = normalizeUrl(url);
Expand Down Expand Up @@ -1048,7 +1056,7 @@ export class Browserbase implements INodeType {
const startResponse = await this.apiCall(
executeFunctions,
'POST',
STAGEHAND_BASE_URL,
baseUrl,
'/v1/sessions/start',
headers,
{
Expand All @@ -1068,7 +1076,7 @@ export class Browserbase implements INodeType {
await this.apiCall(
executeFunctions,
'POST',
STAGEHAND_BASE_URL,
baseUrl,
`/v1/sessions/${sessionId}/navigate`,
headers,
{
Expand Down Expand Up @@ -1123,7 +1131,7 @@ export class Browserbase implements INodeType {
const executeResponse = await this.apiCall(
executeFunctions,
'POST',
STAGEHAND_BASE_URL,
baseUrl,
`/v1/sessions/${sessionId}/agentExecute`,
headers,
{
Expand All @@ -1135,7 +1143,7 @@ export class Browserbase implements INodeType {
await this.apiCall(
executeFunctions,
'POST',
STAGEHAND_BASE_URL,
baseUrl,
`/v1/sessions/${sessionId}/end`,
headers,
{},
Expand Down Expand Up @@ -1163,7 +1171,7 @@ export class Browserbase implements INodeType {
await this.apiCall(
executeFunctions,
'POST',
STAGEHAND_BASE_URL,
baseUrl,
`/v1/sessions/${sessionId}/end`,
headers,
{},
Expand Down Expand Up @@ -1199,12 +1207,20 @@ export class Browserbase implements INodeType {
includeModelApiKey: resource === 'agent' && modelSource === 'userProvidedKey',
});

const useCredentialBaseUrls = this.getNode().typeVersion >= 2.1;
const apiBaseUrl = useCredentialBaseUrls
? normalizeBaseUrl((credentials.baseUrl as string) || API_BASE_URL)
: API_BASE_URL;
const stagehandBaseUrl = useCredentialBaseUrls
? normalizeBaseUrl((credentials.stagehandBaseUrl as string) || STAGEHAND_BASE_URL)
: STAGEHAND_BASE_URL;

if (resource === 'search') {
returnData.push(await node.executeSearch(this, i, headers));
returnData.push(await node.executeSearch(this, i, headers, apiBaseUrl));
} else if (resource === 'fetch') {
returnData.push(await node.executeFetch(this, i, headers));
returnData.push(await node.executeFetch(this, i, headers, apiBaseUrl));
} else {
returnData.push(await node.executeAgent(this, i, headers));
returnData.push(await node.executeAgent(this, i, headers, stagehandBaseUrl));
}
} catch (error) {
if (this.continueOnFail()) {
Expand Down