n8n-nodes-smart-browser-automation 1.6.4 → 1.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/dist/nodes/SmartBrowserAutomation/BrowserSessionManager.d.ts +1 -0
- package/dist/nodes/SmartBrowserAutomation/BrowserSessionManager.js +38 -5
- package/dist/nodes/SmartBrowserAutomation/SmartBrowserAutomation.node.js +55 -52
- package/dist/nodes/SmartBrowserAutomation/SmartBrowserAutomationTools.node.d.ts +5 -0
- package/dist/nodes/SmartBrowserAutomation/SmartBrowserAutomationTools.node.js +121 -0
- package/dist/nodes/SmartBrowserAutomation/jsonSchemaToZod.d.ts +16 -0
- package/dist/nodes/SmartBrowserAutomation/jsonSchemaToZod.js +108 -0
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -54,13 +54,14 @@ Add new credentials for **Smart Browser Automation API**:
|
|
|
54
54
|
|
|
55
55
|
### Mode 1: AI Agent (Automatic)
|
|
56
56
|
|
|
57
|
-
Use with n8n's **AI Agent** node to let AI decide which browser tools to use
|
|
57
|
+
Use with n8n's **AI Agent** node to let AI decide which browser tools to use.
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
Use the dedicated tool node so the agent can discover each MCP tool and its JSON-schema arguments:
|
|
60
|
+
|
|
61
|
+
1. Add **Smart Browser Automation Tools** node
|
|
62
|
+
2. Configure credentials (MCP endpoint + browser mode)
|
|
63
|
+
3. Connect its **Tools** output to **AI Agent**
|
|
64
|
+
4. The agent can now call MCP tools (e.g. `browser_navigate`, `browser_click`) with correct argument schemas
|
|
64
65
|
|
|
65
66
|
**Example AI Agent Workflow**:
|
|
66
67
|
```
|
|
@@ -13,6 +13,7 @@ declare class BrowserSessionManager {
|
|
|
13
13
|
private constructor();
|
|
14
14
|
static getInstance(): BrowserSessionManager;
|
|
15
15
|
initialize(mcpEndpoint: string, useCDP: boolean, cdpEndpoint?: string): Promise<MCPTool[]>;
|
|
16
|
+
private getAllTools;
|
|
16
17
|
callTool(toolName: string, toolArgs?: any): Promise<any>;
|
|
17
18
|
getTools(): MCPTool[];
|
|
18
19
|
listTools(): Promise<MCPTool[]>;
|
|
@@ -21,6 +21,7 @@ class BrowserSessionManager {
|
|
|
21
21
|
// Only initialize if not already done or config changed
|
|
22
22
|
if (this.isInitialized &&
|
|
23
23
|
this.config.mcpEndpoint === mcpEndpoint &&
|
|
24
|
+
this.config.useCDP === useCDP &&
|
|
24
25
|
this.config.cdpEndpoint === cdpEndpoint) {
|
|
25
26
|
return this.tools;
|
|
26
27
|
}
|
|
@@ -64,13 +65,42 @@ class BrowserSessionManager {
|
|
|
64
65
|
throw new Error(`Failed to connect to MCP server via ${transportType} at ${mcpEndpoint}. Error: ${error.message}`);
|
|
65
66
|
}
|
|
66
67
|
this.isInitialized = true;
|
|
67
|
-
this.config = { mcpEndpoint, cdpEndpoint };
|
|
68
|
-
// Fetch available tools from MCP server
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
this.config = { mcpEndpoint, useCDP, cdpEndpoint };
|
|
69
|
+
// Fetch available tools from MCP server (handles pagination)
|
|
70
|
+
this.tools = await this.getAllTools();
|
|
71
|
+
// If requested, connect to an existing browser via CDP
|
|
72
|
+
if (useCDP) {
|
|
73
|
+
if (!cdpEndpoint || String(cdpEndpoint).trim() === '') {
|
|
74
|
+
throw new Error('CDP endpoint is required when Browser Mode is CDP Connection');
|
|
75
|
+
}
|
|
76
|
+
const hasConnectTool = this.tools.some((t) => t.name === 'browser_connect_cdp');
|
|
77
|
+
if (hasConnectTool) {
|
|
78
|
+
const result = await this.mcpClient.callTool({
|
|
79
|
+
name: 'browser_connect_cdp',
|
|
80
|
+
arguments: { endpoint: cdpEndpoint },
|
|
81
|
+
});
|
|
82
|
+
if (result?.isError) {
|
|
83
|
+
throw new Error(`Failed to connect via CDP: ${JSON.stringify(result)}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
72
87
|
return this.tools;
|
|
73
88
|
}
|
|
89
|
+
async getAllTools(cursor) {
|
|
90
|
+
if (!this.mcpClient) {
|
|
91
|
+
throw new Error('MCP client not initialized');
|
|
92
|
+
}
|
|
93
|
+
// SDK supports optional cursor param; keep it loosely typed for compatibility.
|
|
94
|
+
const response = await (cursor
|
|
95
|
+
? this.mcpClient.listTools({ cursor })
|
|
96
|
+
: this.mcpClient.listTools());
|
|
97
|
+
const tools = (response?.tools ?? []);
|
|
98
|
+
const nextCursor = response?.nextCursor;
|
|
99
|
+
if (nextCursor) {
|
|
100
|
+
return tools.concat(await this.getAllTools(nextCursor));
|
|
101
|
+
}
|
|
102
|
+
return tools;
|
|
103
|
+
}
|
|
74
104
|
async callTool(toolName, toolArgs) {
|
|
75
105
|
if (!this.mcpClient || !this.isInitialized) {
|
|
76
106
|
throw new Error('MCP client not initialized. Please configure credentials first.');
|
|
@@ -84,6 +114,9 @@ class BrowserSessionManager {
|
|
|
84
114
|
});
|
|
85
115
|
// Log the response for debugging
|
|
86
116
|
console.log(`[MCP] Tool "${toolName}" response:`, JSON.stringify(result, null, 2));
|
|
117
|
+
if (result?.isError) {
|
|
118
|
+
throw new Error(typeof result?.toolResult === 'string' ? result.toolResult : `Tool returned error: ${JSON.stringify(result)}`);
|
|
119
|
+
}
|
|
87
120
|
return result;
|
|
88
121
|
}
|
|
89
122
|
catch (error) {
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.SmartBrowserAutomation = void 0;
|
|
7
7
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
8
8
|
const BrowserSessionManager_1 = __importDefault(require("./BrowserSessionManager"));
|
|
9
|
+
const jsonSchemaToZod_1 = require("./jsonSchemaToZod");
|
|
9
10
|
class SmartBrowserAutomation {
|
|
10
11
|
description = {
|
|
11
12
|
displayName: 'Smart Browser Automation',
|
|
@@ -142,74 +143,64 @@ class SmartBrowserAutomation {
|
|
|
142
143
|
// Handle Execute Tool operation
|
|
143
144
|
// Get CDP override or use from credentials
|
|
144
145
|
const cdpOverride = this.getNodeParameter('cdpOverride', 0, '');
|
|
145
|
-
// Check if AI Agent sent
|
|
146
|
+
// Check if AI Agent sent tool name in input
|
|
146
147
|
const inputData = items[0]?.json;
|
|
147
|
-
|
|
148
|
-
const aiAction = inputData?.action;
|
|
149
|
-
// Determine tool name: prefer AI input, fallback to manual parameter
|
|
148
|
+
// Determine tool name and parameters
|
|
150
149
|
let toolName;
|
|
151
|
-
|
|
152
|
-
if
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
150
|
+
let toolParams;
|
|
151
|
+
// Check if this is from AI Agent (has 'tool' field in json)
|
|
152
|
+
if (inputData?.tool && typeof inputData.tool === 'string') {
|
|
153
|
+
// AI Agent execution - tool name is in item.json.tool
|
|
154
|
+
toolName = inputData.tool;
|
|
155
|
+
// Extract parameters by removing known n8n/AI fields
|
|
156
|
+
const { tool, action, chatInput, sessionId, toolCallId, name, id, arguments: args, ...rest } = inputData;
|
|
157
|
+
// Use 'arguments' field if present, otherwise use remaining fields
|
|
158
|
+
toolParams = args && typeof args === 'object' ? args : rest;
|
|
159
159
|
}
|
|
160
160
|
else {
|
|
161
|
-
// Manual
|
|
161
|
+
// Manual execution - use node parameters
|
|
162
162
|
toolName = this.getNodeParameter('toolName', 0);
|
|
163
|
-
}
|
|
164
|
-
try {
|
|
165
|
-
// Initialize session if not ready
|
|
166
|
-
if (!sessionManager.isReady()) {
|
|
167
|
-
const cdpUrl = cdpOverride || credentials.cdpEndpoint || '';
|
|
168
|
-
await sessionManager.initialize(credentials.mcpEndpoint, !!cdpUrl, cdpUrl);
|
|
169
|
-
}
|
|
170
|
-
// Handle tool execution
|
|
171
|
-
let toolParams;
|
|
172
163
|
try {
|
|
173
|
-
|
|
174
|
-
if (
|
|
175
|
-
toolParams =
|
|
164
|
+
const rawParams = this.getNodeParameter('toolParameters', 0);
|
|
165
|
+
if (rawParams === undefined || rawParams === null) {
|
|
166
|
+
toolParams = {};
|
|
176
167
|
}
|
|
177
|
-
else {
|
|
178
|
-
|
|
179
|
-
const rawParams = this.getNodeParameter('toolParameters', 0);
|
|
180
|
-
if (rawParams === undefined || rawParams === null) {
|
|
168
|
+
else if (typeof rawParams === 'string') {
|
|
169
|
+
if (!rawParams || rawParams.trim() === '') {
|
|
181
170
|
toolParams = {};
|
|
182
171
|
}
|
|
183
|
-
else if (typeof rawParams === 'string') {
|
|
184
|
-
if (!rawParams || rawParams.trim() === '') {
|
|
185
|
-
toolParams = {};
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
toolParams = JSON.parse(rawParams);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
else if (typeof rawParams === 'object') {
|
|
192
|
-
toolParams = rawParams;
|
|
193
|
-
}
|
|
194
172
|
else {
|
|
195
|
-
|
|
196
|
-
toolParams = JSON.parse(JSON.stringify(rawParams));
|
|
197
|
-
}
|
|
198
|
-
catch (parseError) {
|
|
199
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid parameter type: ${typeof rawParams}`);
|
|
200
|
-
}
|
|
173
|
+
toolParams = JSON.parse(rawParams);
|
|
201
174
|
}
|
|
202
175
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
176
|
+
else if (typeof rawParams === 'object') {
|
|
177
|
+
toolParams = rawParams;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
try {
|
|
181
|
+
toolParams = JSON.parse(JSON.stringify(rawParams));
|
|
182
|
+
}
|
|
183
|
+
catch (parseError) {
|
|
184
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid parameter type: ${typeof rawParams}`);
|
|
185
|
+
}
|
|
208
186
|
}
|
|
209
187
|
}
|
|
210
188
|
catch (error) {
|
|
211
189
|
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to parse tool parameters: ${error.message}. Make sure the parameters are valid JSON.`);
|
|
212
190
|
}
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
// Initialize session if not ready
|
|
194
|
+
if (!sessionManager.isReady()) {
|
|
195
|
+
const cdpUrl = cdpOverride || credentials.cdpEndpoint || '';
|
|
196
|
+
await sessionManager.initialize(credentials.mcpEndpoint, !!cdpUrl, cdpUrl);
|
|
197
|
+
}
|
|
198
|
+
// Ensure toolParams is an object
|
|
199
|
+
if (typeof toolParams !== 'object' ||
|
|
200
|
+
toolParams === null ||
|
|
201
|
+
Array.isArray(toolParams)) {
|
|
202
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Tool parameters must be a JSON object');
|
|
203
|
+
}
|
|
213
204
|
// Special handling for browser_connect_cdp
|
|
214
205
|
if (toolName === 'browser_connect_cdp') {
|
|
215
206
|
const endpoint = toolParams.endpoint || cdpOverride || credentials.cdpEndpoint;
|
|
@@ -231,11 +222,23 @@ class SmartBrowserAutomation {
|
|
|
231
222
|
}
|
|
232
223
|
// Validate tool exists before executing
|
|
233
224
|
const availableTools = await sessionManager.listTools();
|
|
234
|
-
const
|
|
225
|
+
const selectedTool = availableTools.find((tool) => tool.name === toolName);
|
|
226
|
+
const toolExists = Boolean(selectedTool);
|
|
235
227
|
if (!toolExists) {
|
|
236
228
|
const availableToolNames = availableTools.map((t) => t.name).join(', ');
|
|
237
229
|
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Tool '${toolName}' does not exist. Available tools: ${availableToolNames}`);
|
|
238
230
|
}
|
|
231
|
+
// Validate tool parameters against the MCP tool JSON schema (when provided)
|
|
232
|
+
if (selectedTool?.inputSchema) {
|
|
233
|
+
try {
|
|
234
|
+
const schema = await (0, jsonSchemaToZod_1.jsonSchemaToZod)(selectedTool.inputSchema);
|
|
235
|
+
schema.parse(toolParams);
|
|
236
|
+
}
|
|
237
|
+
catch (validationError) {
|
|
238
|
+
const details = validationError?.issues ? JSON.stringify(validationError.issues) : validationError.message;
|
|
239
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid tool parameters for '${toolName}'.`, { description: details });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
239
242
|
// Execute the tool via MCP
|
|
240
243
|
const result = await sessionManager.callTool(toolName, toolParams);
|
|
241
244
|
returnData.push({
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type INodeType, type INodeTypeDescription, type ISupplyDataFunctions, type SupplyData } from 'n8n-workflow';
|
|
2
|
+
export declare class SmartBrowserAutomationTools implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable n8n-nodes-base/node-class-description-inputs-wrong-regular-node */
|
|
3
|
+
/* eslint-disable n8n-nodes-base/node-class-description-outputs-wrong */
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
+
}) : function(o, v) {
|
|
18
|
+
o["default"] = v;
|
|
19
|
+
});
|
|
20
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
21
|
+
var ownKeys = function(o) {
|
|
22
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
23
|
+
var ar = [];
|
|
24
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
25
|
+
return ar;
|
|
26
|
+
};
|
|
27
|
+
return ownKeys(o);
|
|
28
|
+
};
|
|
29
|
+
return function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
38
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
39
|
+
};
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.SmartBrowserAutomationTools = void 0;
|
|
42
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
43
|
+
const BrowserSessionManager_1 = __importDefault(require("./BrowserSessionManager"));
|
|
44
|
+
const jsonSchemaToZod_1 = require("./jsonSchemaToZod");
|
|
45
|
+
class SmartBrowserAutomationTools {
|
|
46
|
+
description = {
|
|
47
|
+
displayName: 'Smart Browser Automation Tools',
|
|
48
|
+
name: 'smartBrowserAutomationTools',
|
|
49
|
+
group: ['transform'],
|
|
50
|
+
version: 1,
|
|
51
|
+
description: 'Expose Smart Browser Automation MCP tools (with JSON-schema args) to AI Agents',
|
|
52
|
+
defaults: {
|
|
53
|
+
name: 'Browser Automation Tools',
|
|
54
|
+
},
|
|
55
|
+
inputs: [],
|
|
56
|
+
outputs: [{ type: n8n_workflow_1.NodeConnectionTypes.AiTool, displayName: 'Tools' }],
|
|
57
|
+
icon: 'file:smartBrowserAutomation.svg',
|
|
58
|
+
credentials: [
|
|
59
|
+
{
|
|
60
|
+
name: 'smartBrowserAutomationApi',
|
|
61
|
+
required: true,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
properties: [
|
|
65
|
+
{
|
|
66
|
+
displayName: 'CDP Endpoint Override',
|
|
67
|
+
name: 'cdpOverride',
|
|
68
|
+
type: 'string',
|
|
69
|
+
default: '',
|
|
70
|
+
placeholder: 'ws://localhost:9222',
|
|
71
|
+
description: 'Override the CDP endpoint from credentials (only used in CDP mode)',
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
async supplyData(itemIndex) {
|
|
76
|
+
const node = this.getNode();
|
|
77
|
+
const credentials = await this.getCredentials('smartBrowserAutomationApi');
|
|
78
|
+
const sessionManager = BrowserSessionManager_1.default.getInstance();
|
|
79
|
+
const cdpOverride = this.getNodeParameter('cdpOverride', itemIndex, '');
|
|
80
|
+
const useCDP = credentials.browserMode === 'cdp';
|
|
81
|
+
const cdpUrl = (cdpOverride || credentials.cdpEndpoint || '').trim();
|
|
82
|
+
try {
|
|
83
|
+
await sessionManager.initialize(credentials.mcpEndpoint, useCDP, useCDP ? cdpUrl : undefined);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
throw new n8n_workflow_1.NodeOperationError(node, `Failed to connect to MCP server: ${error.message}`, {
|
|
87
|
+
itemIndex,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const mcpTools = await sessionManager.listTools();
|
|
91
|
+
if (!mcpTools.length) {
|
|
92
|
+
throw new n8n_workflow_1.NodeOperationError(node, 'MCP Server returned no tools', { itemIndex });
|
|
93
|
+
}
|
|
94
|
+
const { DynamicStructuredTool } = await Promise.resolve().then(() => __importStar(require('langchain/tools')));
|
|
95
|
+
const { Toolkit } = await Promise.resolve().then(() => __importStar(require('langchain/agents')));
|
|
96
|
+
const tools = await Promise.all(mcpTools.map(async (tool) => {
|
|
97
|
+
const schema = await (0, jsonSchemaToZod_1.jsonSchemaToZod)(tool.inputSchema);
|
|
98
|
+
return new DynamicStructuredTool({
|
|
99
|
+
name: tool.name,
|
|
100
|
+
description: tool.description ?? '',
|
|
101
|
+
schema,
|
|
102
|
+
func: async (args) => {
|
|
103
|
+
return await sessionManager.callTool(tool.name, args);
|
|
104
|
+
},
|
|
105
|
+
metadata: { isFromToolkit: true },
|
|
106
|
+
});
|
|
107
|
+
}));
|
|
108
|
+
class SmartBrowserAutomationToolkit extends Toolkit {
|
|
109
|
+
tools;
|
|
110
|
+
constructor(tools) {
|
|
111
|
+
super();
|
|
112
|
+
this.tools = tools;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
response: new SmartBrowserAutomationToolkit(tools),
|
|
117
|
+
closeFunction: async () => await sessionManager.close(),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.SmartBrowserAutomationTools = SmartBrowserAutomationTools;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type JsonSchema = {
|
|
2
|
+
type?: string | string[];
|
|
3
|
+
properties?: Record<string, JsonSchema>;
|
|
4
|
+
required?: string[];
|
|
5
|
+
items?: JsonSchema;
|
|
6
|
+
enum?: Array<string | number | boolean | null>;
|
|
7
|
+
anyOf?: JsonSchema[];
|
|
8
|
+
oneOf?: JsonSchema[];
|
|
9
|
+
allOf?: JsonSchema[];
|
|
10
|
+
additionalProperties?: boolean | JsonSchema;
|
|
11
|
+
default?: unknown;
|
|
12
|
+
description?: string;
|
|
13
|
+
format?: string;
|
|
14
|
+
};
|
|
15
|
+
export type { JsonSchema };
|
|
16
|
+
export declare function jsonSchemaToZod(schema: JsonSchema | undefined): Promise<any>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.jsonSchemaToZod = jsonSchemaToZod;
|
|
37
|
+
async function jsonSchemaToZod(schema) {
|
|
38
|
+
const { z } = await Promise.resolve().then(() => __importStar(require('zod')));
|
|
39
|
+
const toZod = (s) => {
|
|
40
|
+
if (!s)
|
|
41
|
+
return z.any();
|
|
42
|
+
if (Array.isArray(s.oneOf) && s.oneOf.length) {
|
|
43
|
+
return z.union(s.oneOf.map((x) => toZod(x)));
|
|
44
|
+
}
|
|
45
|
+
if (Array.isArray(s.anyOf) && s.anyOf.length) {
|
|
46
|
+
return z.union(s.anyOf.map((x) => toZod(x)));
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(s.allOf) && s.allOf.length) {
|
|
49
|
+
return s.allOf.reduce((acc, cur) => acc.and(toZod(cur)), toZod(s.allOf[0]));
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(s.enum) && s.enum.length) {
|
|
52
|
+
const values = s.enum;
|
|
53
|
+
const allStrings = values.every((v) => typeof v === 'string');
|
|
54
|
+
if (allStrings) {
|
|
55
|
+
return z.enum(values);
|
|
56
|
+
}
|
|
57
|
+
return z.union(values.map((v) => z.literal(v)));
|
|
58
|
+
}
|
|
59
|
+
const type = s.type;
|
|
60
|
+
const types = Array.isArray(type) ? type : type ? [type] : [];
|
|
61
|
+
const allowsNull = types.includes('null');
|
|
62
|
+
const effectiveTypes = types.filter((t) => t !== 'null');
|
|
63
|
+
let base;
|
|
64
|
+
switch (effectiveTypes[0]) {
|
|
65
|
+
case 'string':
|
|
66
|
+
base = z.string();
|
|
67
|
+
break;
|
|
68
|
+
case 'integer':
|
|
69
|
+
base = z.number().int();
|
|
70
|
+
break;
|
|
71
|
+
case 'number':
|
|
72
|
+
base = z.number();
|
|
73
|
+
break;
|
|
74
|
+
case 'boolean':
|
|
75
|
+
base = z.boolean();
|
|
76
|
+
break;
|
|
77
|
+
case 'array':
|
|
78
|
+
base = z.array(toZod(s.items));
|
|
79
|
+
break;
|
|
80
|
+
case 'object': {
|
|
81
|
+
const shape = {};
|
|
82
|
+
const props = s.properties ?? {};
|
|
83
|
+
const required = new Set(s.required ?? []);
|
|
84
|
+
for (const [key, value] of Object.entries(props)) {
|
|
85
|
+
const zodProp = toZod(value);
|
|
86
|
+
shape[key] = required.has(key) ? zodProp : zodProp.optional();
|
|
87
|
+
}
|
|
88
|
+
base = z.object(shape);
|
|
89
|
+
if (s.additionalProperties === false) {
|
|
90
|
+
base = base.strict();
|
|
91
|
+
}
|
|
92
|
+
else if (s.additionalProperties && typeof s.additionalProperties === 'object') {
|
|
93
|
+
base = base.catchall(toZod(s.additionalProperties));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
base = base.passthrough();
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
default:
|
|
101
|
+
base = z.any();
|
|
102
|
+
}
|
|
103
|
+
if (allowsNull)
|
|
104
|
+
base = base.nullable();
|
|
105
|
+
return base;
|
|
106
|
+
};
|
|
107
|
+
return toZod(schema);
|
|
108
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-smart-browser-automation",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.6",
|
|
4
4
|
"description": "n8n node for AI-driven browser automation using MCP",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"n8n-community-node-package",
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
"dist/credentials/SmartBrowserAutomationApi.credentials.js"
|
|
38
38
|
],
|
|
39
39
|
"nodes": [
|
|
40
|
-
"dist/nodes/SmartBrowserAutomation/SmartBrowserAutomation.node.js"
|
|
40
|
+
"dist/nodes/SmartBrowserAutomation/SmartBrowserAutomation.node.js",
|
|
41
|
+
"dist/nodes/SmartBrowserAutomation/SmartBrowserAutomationTools.node.js"
|
|
41
42
|
]
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
@@ -55,6 +56,7 @@
|
|
|
55
56
|
"n8n-workflow": "*"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
|
-
"@modelcontextprotocol/sdk": "^1.17.0"
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.17.0",
|
|
60
|
+
"zod": "^3.23.8"
|
|
59
61
|
}
|
|
60
62
|
}
|