Skip to content

Commit b68b4ec

Browse files
authored
fix: close session after credential test and deprecate project ID field (#8)
1 parent 86130c8 commit b68b4ec

2 files changed

Lines changed: 86 additions & 17 deletions

File tree

credentials/BrowserbaseApi.credentials.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type {
22
IAuthenticateGeneric,
3-
ICredentialTestRequest,
43
ICredentialType,
54
INodeProperties,
65
} from 'n8n-workflow';
@@ -25,12 +24,12 @@ export class BrowserbaseApi implements ICredentialType {
2524
description: 'Your Browserbase API key',
2625
},
2726
{
28-
displayName: 'Browserbase Project ID',
27+
displayName: 'Browserbase Project ID (Deprecated)',
2928
name: 'browserbaseProjectId',
3029
type: 'string',
3130
default: '',
32-
required: true,
33-
description: 'Your Browserbase project ID',
31+
required: false,
32+
description: 'Optional. Your Browserbase project ID (no longer required for new setups)',
3433
},
3534
{
3635
displayName: 'Model API Key',
@@ -48,20 +47,9 @@ export class BrowserbaseApi implements ICredentialType {
4847
properties: {
4948
headers: {
5049
'x-bb-api-key': '={{$credentials.browserbaseApiKey}}',
51-
'x-bb-project-id': '={{$credentials.browserbaseProjectId}}',
5250
'x-model-api-key': '={{$credentials.modelApiKey}}',
5351
},
5452
},
5553
};
5654

57-
test: ICredentialTestRequest = {
58-
request: {
59-
baseURL: 'https://api.stagehand.browserbase.com',
60-
url: '/v1/sessions/start',
61-
method: 'POST',
62-
body: {
63-
modelName: 'openai/gpt-4o',
64-
},
65-
},
66-
};
6755
}

nodes/Browserbase/Browserbase.node.ts

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import {
22
NodeConnectionTypes,
3+
type ICredentialDataDecryptedObject,
4+
type ICredentialTestFunctions,
5+
type ICredentialsDecrypted,
36
type IExecuteFunctions,
7+
type INodeCredentialTestResult,
48
type INodeExecutionData,
59
type INodeType,
610
type INodeTypeDescription,
@@ -30,6 +34,7 @@ export class Browserbase implements INodeType {
3034
{
3135
name: 'browserbaseApi',
3236
required: true,
37+
testedBy: 'browserbaseApiTest',
3338
},
3439
],
3540
properties: [
@@ -613,6 +618,79 @@ export class Browserbase implements INodeType {
613618
],
614619
};
615620

621+
methods = {
622+
credentialTest: {
623+
async browserbaseApiTest(
624+
this: ICredentialTestFunctions,
625+
credential: ICredentialsDecrypted<ICredentialDataDecryptedObject>,
626+
): Promise<INodeCredentialTestResult> {
627+
const { browserbaseApiKey, browserbaseProjectId, modelApiKey } =
628+
credential.data!;
629+
630+
const headers: Record<string, string> = {
631+
Accept: 'application/json',
632+
'Content-Type': 'application/json',
633+
'x-bb-api-key': browserbaseApiKey as string,
634+
'x-model-api-key': modelApiKey as string,
635+
};
636+
if (browserbaseProjectId) {
637+
headers['x-bb-project-id'] = browserbaseProjectId as string;
638+
}
639+
640+
let sessionId: string | undefined;
641+
642+
const httpRequest = this.helpers[
643+
'request' as keyof typeof this.helpers
644+
] as (opts: object) => Promise<Record<string, unknown>>;
645+
646+
try {
647+
const startResponse = await httpRequest({
648+
method: 'POST',
649+
uri: `${BASE_URL}/v1/sessions/start`,
650+
headers,
651+
body: { modelName: 'openai/gpt-4o' },
652+
json: true,
653+
});
654+
655+
const data = startResponse.data as Record<string, unknown> | undefined;
656+
sessionId = (data?.sessionId ??
657+
startResponse.sessionId ??
658+
startResponse.id) as string | undefined;
659+
660+
if (sessionId) {
661+
await httpRequest({
662+
method: 'POST',
663+
uri: `${BASE_URL}/v1/sessions/${sessionId}/end`,
664+
headers,
665+
body: {},
666+
json: true,
667+
});
668+
}
669+
670+
return { status: 'OK', message: 'Connection successful' };
671+
} catch (error) {
672+
if (sessionId) {
673+
try {
674+
await httpRequest({
675+
method: 'POST',
676+
uri: `${BASE_URL}/v1/sessions/${sessionId}/end`,
677+
headers,
678+
body: {},
679+
json: true,
680+
});
681+
} catch {
682+
// Ignore cleanup errors
683+
}
684+
}
685+
686+
const msg =
687+
error instanceof Error ? error.message : String(error);
688+
return { status: 'Error', message: msg };
689+
}
690+
},
691+
},
692+
};
693+
616694
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
617695
const items = this.getInputData();
618696
const returnData: INodeExecutionData[] = [];
@@ -674,13 +752,16 @@ export class Browserbase implements INodeType {
674752

675753
// Get credentials
676754
const credentials = await this.getCredentials('browserbaseApi');
677-
const headers = {
755+
const headers: Record<string, string> = {
678756
Accept: 'application/json',
679757
'Content-Type': 'application/json',
680758
'x-bb-api-key': credentials.browserbaseApiKey as string,
681-
'x-bb-project-id': credentials.browserbaseProjectId as string,
682759
'x-model-api-key': credentials.modelApiKey as string,
683760
};
761+
// We no longer need to set the Project ID, but keeping this here for backwards compatibility
762+
if (credentials.browserbaseProjectId) {
763+
headers['x-bb-project-id'] = credentials.browserbaseProjectId as string;
764+
}
684765

685766
// Helper function to make API calls
686767
const apiCall = async (

0 commit comments

Comments
 (0)