mirror of
				https://github.com/n8n-io/n8n-nodes-starter.git
				synced 2025-10-30 23:02:25 -05:00 
			
		
		
		
	feat: initialize base agent node
This commit is contained in:
		
					parent
					
						
							
								e33348ac69
							
						
					
				
			
			
				commit
				
					
						2fbccb3423
					
				
			
		
					 13 changed files with 8082 additions and 536 deletions
				
			
		
							
								
								
									
										66
									
								
								credentials/BaseApi.credentials.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								credentials/BaseApi.credentials.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | |||
| import { | ||||
| 	IAuthenticateGeneric, | ||||
| 	ICredentialTestRequest, | ||||
| 	ICredentialType, | ||||
| 	INodeProperties, | ||||
| } from 'n8n-workflow'; | ||||
| 
 | ||||
| export class BaseApi implements ICredentialType { | ||||
| 	name = 'baseApi'; | ||||
| 	displayName = 'Base API'; | ||||
| 	documentationUrl = 'https://docs.base.com/'; | ||||
| 	properties: INodeProperties[] = [ | ||||
| 		{ | ||||
| 			displayName: 'Private Key', | ||||
| 			name: 'privateKey', | ||||
| 			type: 'string', | ||||
| 			typeOptions: { | ||||
| 				password: true, | ||||
| 			}, | ||||
| 			default: '', | ||||
| 			required: true, | ||||
| 			description: 'The private key of your Base wallet', | ||||
| 		}, | ||||
| 		{ | ||||
| 			displayName: 'RPC URL', | ||||
| 			name: 'rpcUrl', | ||||
| 			type: 'string', | ||||
| 			default: 'https://api.mainnet-beta.base.com', | ||||
| 			required: true, | ||||
| 			description: 'The URL of the Base RPC node', | ||||
| 		}, | ||||
| 		{ | ||||
| 			displayName: 'OpenAI API Key', | ||||
| 			name: 'openAiApiKey', | ||||
| 			type: 'string', | ||||
| 			typeOptions: { | ||||
| 				password: true, | ||||
| 			}, | ||||
| 			default: '', | ||||
| 			required: true, | ||||
| 			description: 'API key for OpenAI services', | ||||
| 		}, | ||||
| 	]; | ||||
| 
 | ||||
| 	authenticate: IAuthenticateGeneric = { | ||||
| 		type: 'generic', | ||||
| 		properties: { | ||||
| 			headers: { | ||||
| 				'Content-Type': 'application/json', | ||||
| 			}, | ||||
| 		}, | ||||
| 	}; | ||||
| 
 | ||||
| 	test: ICredentialTestRequest = { | ||||
| 		request: { | ||||
| 			baseURL: '={{$credentials.rpcUrl}}', | ||||
| 			url: '/', | ||||
| 			method: 'POST', | ||||
| 			body: { | ||||
| 				jsonrpc: '2.0', | ||||
| 				id: 1, | ||||
| 				method: 'getHealth', | ||||
| 			}, | ||||
| 		}, | ||||
| 	}; | ||||
| }  | ||||
|  | @ -1,56 +0,0 @@ | |||
| import { | ||||
| 	IAuthenticateGeneric, | ||||
| 	ICredentialTestRequest, | ||||
| 	ICredentialType, | ||||
| 	INodeProperties, | ||||
| } from 'n8n-workflow'; | ||||
| 
 | ||||
| export class ExampleCredentialsApi implements ICredentialType { | ||||
| 	name = 'exampleCredentialsApi'; | ||||
| 	displayName = 'Example Credentials API'; | ||||
| 	properties: INodeProperties[] = [ | ||||
| 		// The credentials to get from user and save encrypted.
 | ||||
| 		// Properties can be defined exactly in the same way
 | ||||
| 		// as node properties.
 | ||||
| 		{ | ||||
| 			displayName: 'User Name', | ||||
| 			name: 'username', | ||||
| 			type: 'string', | ||||
| 			default: '', | ||||
| 		}, | ||||
| 		{ | ||||
| 			displayName: 'Password', | ||||
| 			name: 'password', | ||||
| 			type: 'string', | ||||
| 			typeOptions: { | ||||
| 				password: true, | ||||
| 			}, | ||||
| 			default: '', | ||||
| 		}, | ||||
| 	]; | ||||
| 
 | ||||
| 	// This credential is currently not used by any node directly
 | ||||
| 	// but the HTTP Request node can use it to make requests.
 | ||||
| 	// The credential is also testable due to the `test` property below
 | ||||
| 	authenticate: IAuthenticateGeneric = { | ||||
| 		type: 'generic', | ||||
| 		properties: { | ||||
| 			auth: { | ||||
| 				username: '={{ $credentials.username }}', | ||||
| 				password: '={{ $credentials.password }}', | ||||
| 			}, | ||||
| 			qs: { | ||||
| 				// Send this as part of the query string
 | ||||
| 				n8n: 'rocks', | ||||
| 			}, | ||||
| 		}, | ||||
| 	}; | ||||
| 
 | ||||
| 	// The block below tells how this credential can be tested
 | ||||
| 	test: ICredentialTestRequest = { | ||||
| 		request: { | ||||
| 			baseURL: 'https://example.com/', | ||||
| 			url: '', | ||||
| 		}, | ||||
| 	}; | ||||
| } | ||||
|  | @ -1,50 +0,0 @@ | |||
| import { | ||||
| 	IAuthenticateGeneric, | ||||
| 	ICredentialTestRequest, | ||||
| 	ICredentialType, | ||||
| 	INodeProperties, | ||||
| } from 'n8n-workflow'; | ||||
| 
 | ||||
| export class HttpBinApi implements ICredentialType { | ||||
| 	name = 'httpbinApi'; | ||||
| 	displayName = 'HttpBin API'; | ||||
| 	documentationUrl = '<your-docs-url>'; | ||||
| 	properties: INodeProperties[] = [ | ||||
| 		{ | ||||
| 			displayName: 'Token', | ||||
| 			name: 'token', | ||||
| 			type: 'string', | ||||
| 			default: '', | ||||
| 			typeOptions: { | ||||
| 				password: true, | ||||
| 			} | ||||
| 		}, | ||||
| 		{ | ||||
| 			displayName: 'Domain', | ||||
| 			name: 'domain', | ||||
| 			type: 'string', | ||||
| 			default: 'https://httpbin.org', | ||||
| 		}, | ||||
| 	]; | ||||
| 
 | ||||
| 	// This allows the credential to be used by other parts of n8n
 | ||||
| 	// stating how this credential is injected as part of the request
 | ||||
| 	// An example is the Http Request node that can make generic calls
 | ||||
| 	// reusing this credential
 | ||||
| 	authenticate: IAuthenticateGeneric = { | ||||
| 		type: 'generic', | ||||
| 		properties: { | ||||
| 			headers: { | ||||
| 				Authorization: '={{"Bearer " + $credentials.token}}', | ||||
| 			}, | ||||
| 		}, | ||||
| 	}; | ||||
| 
 | ||||
| 	// The block below tells how this credential can be tested
 | ||||
| 	test: ICredentialTestRequest = { | ||||
| 		request: { | ||||
| 			baseURL: '={{$credentials?.domain}}', | ||||
| 			url: '/bearer', | ||||
| 		}, | ||||
| 	}; | ||||
| } | ||||
							
								
								
									
										272
									
								
								nodes/BaseAgent/BaseAgent.node.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								nodes/BaseAgent/BaseAgent.node.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,272 @@ | |||
| import { | ||||
| 	IExecuteFunctions, | ||||
| 	INodeExecutionData, | ||||
| 	INodeType, | ||||
| 	INodeTypeDescription, | ||||
| 	NodeOperationError, | ||||
| } from 'n8n-workflow'; | ||||
| 
 | ||||
| class BaseAgent implements INodeType { | ||||
| 	description: INodeTypeDescription = { | ||||
| 		displayName: 'Base Agent', | ||||
| 		name: 'baseAgent', | ||||
| 		icon: 'file:base.svg', | ||||
| 		group: ['blockchain'], | ||||
| 		version: 1, | ||||
| 		subtitle: '={{$parameter["operation"]}}', | ||||
| 		description: 'Interact with Base onchain AI agents', | ||||
| 		defaults: { | ||||
| 			name: 'Base Agent', | ||||
| 		}, | ||||
| 		inputs: ['main'], | ||||
| 		outputs: ['main'], | ||||
| 		credentials: [ | ||||
| 			{ | ||||
| 				name: 'baseApi', | ||||
| 				required: true, | ||||
| 			}, | ||||
| 		], | ||||
| 		properties: [ | ||||
| 			{ | ||||
| 				displayName: 'Operation', | ||||
| 				name: 'operation', | ||||
| 				type: 'options', | ||||
| 				noDataExpression: true, | ||||
| 				// eslint-disable-next-line n8n-nodes-base/node-param-options-type-unsorted-items
 | ||||
| 				options: [ | ||||
| 					{ | ||||
| 						name: 'Create Token', | ||||
| 						value: 'createToken', | ||||
| 						description: 'Create a new token', | ||||
| 						action: 'Create a new token', | ||||
| 					}, | ||||
| 					{ | ||||
| 						name: 'Transfer Token', | ||||
| 						value: 'transferToken', | ||||
| 						description: 'Transfer tokens', | ||||
| 						action: 'Transfer tokens', | ||||
| 					}, | ||||
| 					{ | ||||
| 						name: 'Get Token Balances', | ||||
| 						value: 'getTokenBalances', | ||||
| 						description: 'Get all token balances for a wallet', | ||||
| 						action: 'Get token balances', | ||||
| 					}, | ||||
| 					{ | ||||
| 						name: 'Get Single Token Balance', | ||||
| 						value: 'getSingleBalance', | ||||
| 						description: 'Get balance for a specific token', | ||||
| 						action: 'Get single token balance', | ||||
| 					}, | ||||
| 					{ | ||||
| 						name: 'Get Other Wallet Balance', | ||||
| 						value: 'getOtherBalance', | ||||
| 						description: 'Get token balance for another wallet', | ||||
| 						action: 'Get other wallet balance', | ||||
| 					}, | ||||
| 					{ | ||||
| 						name: 'Close Empty Token Accounts', | ||||
| 						value: 'closeEmptyTokenAccounts', | ||||
| 						action: 'Close empty token accounts', | ||||
| 					}, | ||||
| 					{ | ||||
| 						name: 'Request Faucet Funds', | ||||
| 						value: 'requestFaucet', | ||||
| 						description: 'Request SOL from faucet (devnet/testnet)', | ||||
| 						action: 'Request faucet funds', | ||||
| 					}, | ||||
| 					{ | ||||
| 						name: 'Get Network TPS', | ||||
| 						value: 'getTPS', | ||||
| 						description: 'Get current network TPS', | ||||
| 						action: 'Get network TPS', | ||||
| 					}, | ||||
| 					{ | ||||
| 						name: 'Get Wallet Address', | ||||
| 						value: 'getWalletAddress', | ||||
| 						description: 'Get current wallet address', | ||||
| 						action: 'Get wallet address', | ||||
| 					}, | ||||
| 				], | ||||
| 				default: 'createToken', | ||||
| 			}, | ||||
| 			// Token Creation Parameters
 | ||||
| 			{ | ||||
| 				displayName: 'Token Name', | ||||
| 				name: 'tokenName', | ||||
| 				type: 'string', | ||||
| 				typeOptions: { password: true }, | ||||
| 				required: true, | ||||
| 				displayOptions: { | ||||
| 					show: { | ||||
| 						operation: ['createToken'], | ||||
| 					}, | ||||
| 				}, | ||||
| 				default: '', | ||||
| 				description: 'Name of the token to create', | ||||
| 			}, | ||||
| 			{ | ||||
| 				displayName: 'Token Symbol', | ||||
| 				name: 'tokenSymbol', | ||||
| 				type: 'string', | ||||
| 				typeOptions: { password: true }, | ||||
| 				required: true, | ||||
| 				displayOptions: { | ||||
| 					show: { | ||||
| 						operation: ['createToken'], | ||||
| 					}, | ||||
| 				}, | ||||
| 				default: '', | ||||
| 				description: 'Symbol of the token to create', | ||||
| 			}, | ||||
| 			{ | ||||
| 				displayName: 'Decimals', | ||||
| 				name: 'decimals', | ||||
| 				type: 'number', | ||||
| 				displayOptions: { | ||||
| 					show: { | ||||
| 						operation: ['createToken'], | ||||
| 					}, | ||||
| 				}, | ||||
| 				default: 9, | ||||
| 				description: 'Number of decimal places for the token', | ||||
| 			}, | ||||
| 			{ | ||||
| 				displayName: 'Initial Supply', | ||||
| 				name: 'initialSupply', | ||||
| 				type: 'number', | ||||
| 				displayOptions: { | ||||
| 					show: { | ||||
| 						operation: ['createToken'], | ||||
| 					}, | ||||
| 				}, | ||||
| 				default: 0, | ||||
| 				description: 'Initial supply of tokens to mint', | ||||
| 			}, | ||||
| 			// Transfer Parameters
 | ||||
| 			{ | ||||
| 				displayName: 'Recipient Address', | ||||
| 				name: 'recipientAddress', | ||||
| 				type: 'string', | ||||
| 				required: true, | ||||
| 				displayOptions: { | ||||
| 					show: { | ||||
| 						operation: ['transferToken'], | ||||
| 					}, | ||||
| 				}, | ||||
| 				default: '', | ||||
| 				description: 'Recipient wallet address', | ||||
| 			}, | ||||
| 			{ | ||||
| 				displayName: 'Amount', | ||||
| 				name: 'amount', | ||||
| 				type: 'number', | ||||
| 				required: true, | ||||
| 				displayOptions: { | ||||
| 					show: { | ||||
| 						operation: ['transferToken'], | ||||
| 					}, | ||||
| 				}, | ||||
| 				default: 0, | ||||
| 				description: 'Amount to transfer', | ||||
| 			}, | ||||
| 			{ | ||||
| 				displayName: 'Token Address', | ||||
| 				name: 'tokenAddress', | ||||
| 				type: 'string', | ||||
| 				typeOptions: { password: true }, | ||||
| 				displayOptions: { | ||||
| 					show: { | ||||
| 						operation: ['transferToken', 'getSingleBalance'], | ||||
| 					}, | ||||
| 				}, | ||||
| 				default: '', | ||||
| 				description: 'SPL token address (leave empty for SOL)', | ||||
| 			}, | ||||
| 			// Balance Parameters
 | ||||
| 			{ | ||||
| 				displayName: 'Wallet Address', | ||||
| 				name: 'walletAddress', | ||||
| 				type: 'string', | ||||
| 				displayOptions: { | ||||
| 					show: { | ||||
| 						operation: ['getTokenBalances', 'getOtherBalance'], | ||||
| 					}, | ||||
| 				}, | ||||
| 				default: '', | ||||
| 				description: 'Wallet address to check balances for (leave empty for own wallet)', | ||||
| 			}, | ||||
| 			{ | ||||
| 				displayName: 'Token Address for Other Wallet', | ||||
| 				name: 'otherTokenAddress', | ||||
| 				type: 'string', | ||||
| 				typeOptions: { password: true }, | ||||
| 				displayOptions: { | ||||
| 					show: { | ||||
| 						operation: ['getOtherBalance'], | ||||
| 					}, | ||||
| 				}, | ||||
| 				default: '', | ||||
| 				description: 'Token address to check balance for (leave empty for SOL)', | ||||
| 			}, | ||||
| 		], | ||||
| 	}; | ||||
| 
 | ||||
| 	 | ||||
| 
 | ||||
| 	async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { | ||||
| 		const items = this.getInputData(); | ||||
| 		const returnData: INodeExecutionData[] = []; | ||||
| 		const operation = this.getNodeParameter('operation', 0) as string; | ||||
| 		 | ||||
| 		// Get credentials
 | ||||
| 		const credentials = await this.getCredentials('baseApi'); | ||||
| 		const rpcUrl = credentials.rpcUrl; | ||||
| 		rpcUrl | ||||
| 		// Initialize Wallet
 | ||||
| 		 | ||||
| 		// Initialize Base Agent Kit
 | ||||
| 		 | ||||
| 
 | ||||
| 		for (let i = 0; i < items.length; i++) { | ||||
| 			try { | ||||
| 				let result; | ||||
| 				 | ||||
| 				switch (operation) { | ||||
| 
 | ||||
| 					//TODO: define base on chain actions
 | ||||
| 					case 'transferToken': | ||||
| 						// const recipientAddress = new PublicKey(this.getNodeParameter('recipientAddress', i) as string);
 | ||||
| 						// const amount = this.getNodeParameter('amount', i) as number;
 | ||||
| 						// const tokenAddress = this.getNodeParameter('tokenAddress', i) as string;
 | ||||
| 						// const mintAddress = tokenAddress ? new PublicKey(tokenAddress) : undefined;
 | ||||
| 						// result = await agent.methods.transfer(agent, recipientAddress, amount, mintAddress);
 | ||||
| 						break; | ||||
| 
 | ||||
| 					 | ||||
| 					default: | ||||
| 						throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not supported!`); | ||||
| 				} | ||||
| 
 | ||||
| 				returnData.push({ | ||||
| 					json: {result}, | ||||
| 				}); | ||||
| 			} catch (error) { | ||||
| 				if (this.continueOnFail()) { | ||||
| 					returnData.push({ | ||||
| 						json: { | ||||
| 							error: error.message, | ||||
| 						}, | ||||
| 					}); | ||||
| 					continue; | ||||
| 				} | ||||
| 				throw error; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		return [returnData]; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Export the class
 | ||||
| export { BaseAgent };  | ||||
							
								
								
									
										14
									
								
								nodes/BaseAgent/base.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								nodes/BaseAgent/base.svg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| <svg width="46" height="46" viewBox="0 0 46 46" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||||
| <g filter="url(#filter0_b_139_1266)"> | ||||
| <rect width="46" height="46" rx="23" fill="black" fill-opacity="0.9"/> | ||||
| <path d="M22.9803 34.3703C29.2728 34.3703 34.3739 29.2796 34.3739 23.0001C34.3739 16.7205 29.2728 11.6299 22.9803 11.6299C17.0104 11.6299 12.1129 16.212 11.6265 22.0443H26.6861V23.9558H11.6265C12.1129 29.7882 17.0104 34.3703 22.9803 34.3703Z" fill="#E3E7E9"/> | ||||
| </g> | ||||
| <defs> | ||||
| <filter id="filter0_b_139_1266" x="-14" y="-14" width="74" height="74" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> | ||||
| <feFlood flood-opacity="0" result="BackgroundImageFix"/> | ||||
| <feGaussianBlur in="BackgroundImageFix" stdDeviation="7"/> | ||||
| <feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_139_1266"/> | ||||
| <feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_139_1266" result="shape"/> | ||||
| </filter> | ||||
| </defs> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 939 B | 
|  | @ -1,76 +0,0 @@ | |||
| import type { | ||||
| 	IExecuteFunctions, | ||||
| 	INodeExecutionData, | ||||
| 	INodeType, | ||||
| 	INodeTypeDescription, | ||||
| } from 'n8n-workflow'; | ||||
| import { NodeConnectionType, NodeOperationError } from 'n8n-workflow'; | ||||
| 
 | ||||
| export class ExampleNode implements INodeType { | ||||
| 	description: INodeTypeDescription = { | ||||
| 		displayName: 'Example Node', | ||||
| 		name: 'exampleNode', | ||||
| 		group: ['transform'], | ||||
| 		version: 1, | ||||
| 		description: 'Basic Example Node', | ||||
| 		defaults: { | ||||
| 			name: 'Example Node', | ||||
| 		}, | ||||
| 		inputs: [NodeConnectionType.Main], | ||||
| 		outputs: [NodeConnectionType.Main], | ||||
| 		properties: [ | ||||
| 			// Node properties which the user gets displayed and
 | ||||
| 			// can change on the node.
 | ||||
| 			{ | ||||
| 				displayName: 'My String', | ||||
| 				name: 'myString', | ||||
| 				type: 'string', | ||||
| 				default: '', | ||||
| 				placeholder: 'Placeholder value', | ||||
| 				description: 'The description text', | ||||
| 			}, | ||||
| 		], | ||||
| 	}; | ||||
| 
 | ||||
| 	// The function below is responsible for actually doing whatever this node
 | ||||
| 	// is supposed to do. In this case, we're just appending the `myString` property
 | ||||
| 	// with whatever the user has entered.
 | ||||
| 	// You can make async calls and use `await`.
 | ||||
| 	async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { | ||||
| 		const items = this.getInputData(); | ||||
| 
 | ||||
| 		let item: INodeExecutionData; | ||||
| 		let myString: string; | ||||
| 
 | ||||
| 		// Iterates over all input items and add the key "myString" with the
 | ||||
| 		// value the parameter "myString" resolves to.
 | ||||
| 		// (This could be a different value for each item in case it contains an expression)
 | ||||
| 		for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { | ||||
| 			try { | ||||
| 				myString = this.getNodeParameter('myString', itemIndex, '') as string; | ||||
| 				item = items[itemIndex]; | ||||
| 
 | ||||
| 				item.json.myString = myString; | ||||
| 			} catch (error) { | ||||
| 				// This node should never fail but we want to showcase how
 | ||||
| 				// to handle errors.
 | ||||
| 				if (this.continueOnFail()) { | ||||
| 					items.push({ json: this.getInputData(itemIndex)[0].json, error, pairedItem: itemIndex }); | ||||
| 				} else { | ||||
| 					// Adding `itemIndex` allows other workflows to handle this error
 | ||||
| 					if (error.context) { | ||||
| 						// If the error thrown already contains the context property,
 | ||||
| 						// only append the itemIndex
 | ||||
| 						error.context.itemIndex = itemIndex; | ||||
| 						throw error; | ||||
| 					} | ||||
| 					throw new NodeOperationError(this.getNode(), error, { | ||||
| 						itemIndex, | ||||
| 					}); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return [items]; | ||||
| 	} | ||||
| } | ||||
|  | @ -1,18 +0,0 @@ | |||
| { | ||||
| 	"node": "n8n-nodes-base.httpbin", | ||||
| 	"nodeVersion": "1.0", | ||||
| 	"codexVersion": "1.0", | ||||
| 	"categories": ["Development", "Developer Tools"], | ||||
| 	"resources": { | ||||
| 		"credentialDocumentation": [ | ||||
| 			{ | ||||
| 				"url": "http://httpbin.org/#/Auth/get_bearer" | ||||
| 			} | ||||
| 		], | ||||
| 		"primaryDocumentation": [ | ||||
| 			{ | ||||
| 				"url": "http://httpbin.org/" | ||||
| 			} | ||||
| 		] | ||||
| 	} | ||||
| } | ||||
|  | @ -1,62 +0,0 @@ | |||
| import { INodeType, INodeTypeDescription } from 'n8n-workflow'; | ||||
| import { httpVerbFields, httpVerbOperations } from './HttpVerbDescription'; | ||||
| 
 | ||||
| export class HttpBin implements INodeType { | ||||
| 	description: INodeTypeDescription = { | ||||
| 		displayName: 'HttpBin', | ||||
| 		name: 'httpBin', | ||||
| 		icon: 'file:httpbin.svg', | ||||
| 		group: ['transform'], | ||||
| 		version: 1, | ||||
| 		subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', | ||||
| 		description: 'Interact with HttpBin API', | ||||
| 		defaults: { | ||||
| 			name: 'HttpBin', | ||||
| 		}, | ||||
| 		inputs: ['main'], | ||||
| 		outputs: ['main'], | ||||
| 		credentials: [ | ||||
| 			{ | ||||
| 				name: 'httpbinApi', | ||||
| 				required: false, | ||||
| 			}, | ||||
| 		], | ||||
| 		requestDefaults: { | ||||
| 			baseURL: 'https://httpbin.org', | ||||
| 			url: '', | ||||
| 			headers: { | ||||
| 				Accept: 'application/json', | ||||
| 				'Content-Type': 'application/json', | ||||
| 			}, | ||||
| 		}, | ||||
| 		/** | ||||
| 		 * In the properties array we have two mandatory options objects required | ||||
| 		 * | ||||
| 		 * [Resource & Operation] | ||||
| 		 * | ||||
| 		 * https://docs.n8n.io/integrations/creating-nodes/code/create-first-node/#resources-and-operations
 | ||||
| 		 * | ||||
| 		 * In our example, the operations are separated into their own file (HTTPVerbDescription.ts) | ||||
| 		 * to keep this class easy to read. | ||||
| 		 * | ||||
| 		 */ | ||||
| 		properties: [ | ||||
| 			{ | ||||
| 				displayName: 'Resource', | ||||
| 				name: 'resource', | ||||
| 				type: 'options', | ||||
| 				noDataExpression: true, | ||||
| 				options: [ | ||||
| 					{ | ||||
| 						name: 'HTTP Verb', | ||||
| 						value: 'httpVerb', | ||||
| 					}, | ||||
| 				], | ||||
| 				default: 'httpVerb', | ||||
| 			}, | ||||
| 
 | ||||
| 			...httpVerbOperations, | ||||
| 			...httpVerbFields, | ||||
| 		], | ||||
| 	}; | ||||
| } | ||||
|  | @ -1,248 +0,0 @@ | |||
| import { INodeProperties } from 'n8n-workflow'; | ||||
| 
 | ||||
| // When the resource `httpVerb` is selected, this `operation` parameter will be shown.
 | ||||
| export const httpVerbOperations: INodeProperties[] = [ | ||||
| 	{ | ||||
| 		displayName: 'Operation', | ||||
| 		name: 'operation', | ||||
| 		type: 'options', | ||||
| 		noDataExpression: true, | ||||
| 
 | ||||
| 		displayOptions: { | ||||
| 			show: { | ||||
| 				resource: ['httpVerb'], | ||||
| 			}, | ||||
| 		}, | ||||
| 		options: [ | ||||
| 			{ | ||||
| 				name: 'GET', | ||||
| 				value: 'get', | ||||
| 				description: 'Perform a GET request', | ||||
| 				routing: { | ||||
| 					request: { | ||||
| 						method: 'GET', | ||||
| 						url: '/get', | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name: 'DELETE', | ||||
| 				value: 'delete', | ||||
| 				description: 'Perform a DELETE request', | ||||
| 				routing: { | ||||
| 					request: { | ||||
| 						method: 'DELETE', | ||||
| 						url: '/delete', | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		], | ||||
| 		default: 'get', | ||||
| 	}, | ||||
| ]; | ||||
| 
 | ||||
| // Here we define what to show when the `get` operation is selected.
 | ||||
| // We do that by adding `operation: ["get"]` to `displayOptions.show`
 | ||||
| const getOperation: INodeProperties[] = [ | ||||
| 	{ | ||||
| 		displayName: 'Type of Data', | ||||
| 		name: 'typeofData', | ||||
| 		default: 'queryParameter', | ||||
| 		description: 'Select type of data to send [Query Parameters]', | ||||
| 		displayOptions: { | ||||
| 			show: { | ||||
| 				resource: ['httpVerb'], | ||||
| 				operation: ['get'], | ||||
| 			}, | ||||
| 		}, | ||||
| 		type: 'options', | ||||
| 		options: [ | ||||
| 			{ | ||||
| 				name: 'Query', | ||||
| 				value: 'queryParameter', | ||||
| 			}, | ||||
| 		], | ||||
| 		required: true, | ||||
| 	}, | ||||
| 	{ | ||||
| 		displayName: 'Query Parameters', | ||||
| 		name: 'arguments', | ||||
| 		default: {}, | ||||
| 		description: "The request's query parameters", | ||||
| 		displayOptions: { | ||||
| 			show: { | ||||
| 				resource: ['httpVerb'], | ||||
| 				operation: ['get'], | ||||
| 			}, | ||||
| 		}, | ||||
| 		options: [ | ||||
| 			{ | ||||
| 				name: 'keyvalue', | ||||
| 				displayName: 'Key:Value', | ||||
| 				values: [ | ||||
| 					{ | ||||
| 						displayName: 'Key', | ||||
| 						name: 'key', | ||||
| 						type: 'string', | ||||
| 						default: '', | ||||
| 						required: true, | ||||
| 						description: 'Key of query parameter', | ||||
| 					}, | ||||
| 					{ | ||||
| 						displayName: 'Value', | ||||
| 						name: 'value', | ||||
| 						type: 'string', | ||||
| 						default: '', | ||||
| 						routing: { | ||||
| 							send: { | ||||
| 								property: '={{$parent.key}}', | ||||
| 								type: 'query', | ||||
| 							}, | ||||
| 						}, | ||||
| 						required: true, | ||||
| 						description: 'Value of query parameter', | ||||
| 					}, | ||||
| 				], | ||||
| 			}, | ||||
| 		], | ||||
| 		type: 'fixedCollection', | ||||
| 		typeOptions: { | ||||
| 			multipleValues: true, | ||||
| 		}, | ||||
| 	}, | ||||
| ]; | ||||
| 
 | ||||
| // Here we define what to show when the DELETE Operation is selected.
 | ||||
| // We do that by adding `operation: ["delete"]` to `displayOptions.show`
 | ||||
| const deleteOperation: INodeProperties[] = [ | ||||
| 	{ | ||||
| 		displayName: 'Type of Data', | ||||
| 		name: 'typeofData', | ||||
| 		default: 'queryParameter', | ||||
| 		description: 'Select type of data to send [Query Parameter Arguments, JSON-Body]', | ||||
| 		displayOptions: { | ||||
| 			show: { | ||||
| 				resource: ['httpVerb'], | ||||
| 				operation: ['delete'], | ||||
| 			}, | ||||
| 		}, | ||||
| 		options: [ | ||||
| 			{ | ||||
| 				name: 'Query', | ||||
| 				value: 'queryParameter', | ||||
| 			}, | ||||
| 			{ | ||||
| 				name: 'JSON', | ||||
| 				value: 'jsonData', | ||||
| 			}, | ||||
| 		], | ||||
| 		required: true, | ||||
| 		type: 'options', | ||||
| 	}, | ||||
| 	{ | ||||
| 		displayName: 'Query Parameters', | ||||
| 		name: 'arguments', | ||||
| 		default: {}, | ||||
| 		description: "The request's query parameters", | ||||
| 		displayOptions: { | ||||
| 			show: { | ||||
| 				resource: ['httpVerb'], | ||||
| 				operation: ['delete'], | ||||
| 				typeofData: ['queryParameter'], | ||||
| 			}, | ||||
| 		}, | ||||
| 		options: [ | ||||
| 			{ | ||||
| 				name: 'keyvalue', | ||||
| 				displayName: 'Key:Value', | ||||
| 				values: [ | ||||
| 					{ | ||||
| 						displayName: 'Key', | ||||
| 						name: 'key', | ||||
| 						type: 'string', | ||||
| 						default: '', | ||||
| 						required: true, | ||||
| 						description: 'Key of query parameter', | ||||
| 					}, | ||||
| 					{ | ||||
| 						displayName: 'Value', | ||||
| 						name: 'value', | ||||
| 						type: 'string', | ||||
| 						default: '', | ||||
| 						routing: { | ||||
| 							send: { | ||||
| 								property: '={{$parent.key}}', | ||||
| 								type: 'query', | ||||
| 							}, | ||||
| 						}, | ||||
| 						required: true, | ||||
| 						description: 'Value of query parameter', | ||||
| 					}, | ||||
| 				], | ||||
| 			}, | ||||
| 		], | ||||
| 		type: 'fixedCollection', | ||||
| 		typeOptions: { | ||||
| 			multipleValues: true, | ||||
| 		}, | ||||
| 	}, | ||||
| 	{ | ||||
| 		displayName: 'JSON Object', | ||||
| 		name: 'arguments', | ||||
| 		default: {}, | ||||
| 		description: "The request's JSON properties", | ||||
| 		displayOptions: { | ||||
| 			show: { | ||||
| 				resource: ['httpVerb'], | ||||
| 				operation: ['delete'], | ||||
| 				typeofData: ['jsonData'], | ||||
| 			}, | ||||
| 		}, | ||||
| 		options: [ | ||||
| 			{ | ||||
| 				name: 'keyvalue', | ||||
| 				displayName: 'Key:Value', | ||||
| 				values: [ | ||||
| 					{ | ||||
| 						displayName: 'Key', | ||||
| 						name: 'key', | ||||
| 						type: 'string', | ||||
| 						default: '', | ||||
| 						required: true, | ||||
| 						description: 'Key of JSON property', | ||||
| 					}, | ||||
| 					{ | ||||
| 						displayName: 'Value', | ||||
| 						name: 'value', | ||||
| 						type: 'string', | ||||
| 						default: '', | ||||
| 						routing: { | ||||
| 							send: { | ||||
| 								property: '={{$parent.key}}', | ||||
| 								type: 'body', | ||||
| 							}, | ||||
| 						}, | ||||
| 						required: true, | ||||
| 						description: 'Value of JSON property', | ||||
| 					}, | ||||
| 				], | ||||
| 			}, | ||||
| 		], | ||||
| 		type: 'fixedCollection', | ||||
| 		typeOptions: { | ||||
| 			multipleValues: true, | ||||
| 		}, | ||||
| 	}, | ||||
| ]; | ||||
| 
 | ||||
| export const httpVerbFields: INodeProperties[] = [ | ||||
| 	/* -------------------------------------------------------------------------- */ | ||||
| 	/*                                httpVerb:get                                */ | ||||
| 	/* -------------------------------------------------------------------------- */ | ||||
| 	...getOperation, | ||||
| 
 | ||||
| 	/* -------------------------------------------------------------------------- */ | ||||
| 	/*                              httpVerb:delete                               */ | ||||
| 	/* -------------------------------------------------------------------------- */ | ||||
| 	...deleteOperation, | ||||
| ]; | ||||
|  | @ -1,18 +0,0 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="32px" height="32px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">  <image id="image0" width="32" height="32" x="0" y="0" | ||||
|     href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAABGdBTUEAALGPC/xhBQAAACBjSFJN | ||||
| AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElN | ||||
| RQfmBg4UAC/TqOZZAAACA0lEQVRIx5XVv09TURwF8M+jFHDSyRkGFhPAEfyRdDHi5uriXyDoYgKT | ||||
| MJDWzUT/Ahf/AiOEpajEgCESmpiYmDCxGowDTYE+h76+vte+15Zzk753b7733HNO772PbEw7ECba | ||||
| genswtEcgl0/PHARV72066YrIDSZ6k8KBym4741r0XsB284TdUX8chn1zrzwJUmw4KFXPqjFE0Y0 | ||||
| u5YKEhpmfLZuy7f2wLKGI8WhDRYdaVhurdTCidmU5P44N+skaaGQH1IfFFrOYMotT932zNgQExve | ||||
| OfTeT8dtBceO3TFlOyopY7UPxV+/fWyn3Y0xrFhJjZWFXhs12pKdRO9ObGSuyB8Xbd9JjMjDc6HQ | ||||
| IcrKqAiVe8vyCEJPrGBWxZYqqtZt9RbmHabAvAAVdVUlJTvWshbMt0AYn40OmlchSKOePTyYIMQn | ||||
| rb8yI8TsDCrRs4od7Jv3KOoPGWKboBqp2LN3FQvdO7EPshSsRSTXrSop2cSiiUGkG/bj2JqaQiHW | ||||
| 4nv50mFcu28j30KQarAnEPhuzvwwGYQ975vx7+JwGXTjTIAzoYlhCArR5d0KkfauqJAVY6+FG5hD | ||||
| OS6veqyCuSiTAQT/jKmlQtyxIBCoZV28HQvN6LuQvJFC4xjvibfYOZUdUXd9taTWJbOubiIVXmjG | ||||
| W/fs9qpZcpr6pOe1U0udSf8BR7ef4yxyOskAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjItMDYtMTRU | ||||
| MTc6MDA6NDcrMDM6MDBfo1sRAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDIyLTA2LTE0VDE3OjAwOjQ3 | ||||
| KzAzOjAwLv7jrQAAAABJRU5ErkJggg==" /> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										7723
									
								
								package-lock.json
									
										
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										7723
									
								
								package-lock.json
									
										
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -36,12 +36,10 @@ | |||
|   "n8n": { | ||||
|     "n8nNodesApiVersion": 1, | ||||
|     "credentials": [ | ||||
|       "dist/credentials/ExampleCredentialsApi.credentials.js", | ||||
|       "dist/credentials/HttpBinApi.credentials.js" | ||||
|       "dist/credentials/BaseApi.credentials.js" | ||||
|     ], | ||||
|     "nodes": [ | ||||
|       "dist/nodes/ExampleNode/ExampleNode.node.js", | ||||
|       "dist/nodes/HttpBin/HttpBin.node.js" | ||||
|       "dist/nodes/BaseAgent/BaseAgent.node.js" | ||||
|     ] | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|  |  | |||
							
								
								
									
										9
									
								
								pnpm-lock.yaml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										9
									
								
								pnpm-lock.yaml
									
										
									
										generated
									
									
									
								
							|  | @ -7,6 +7,10 @@ settings: | |||
| importers: | ||||
| 
 | ||||
|   .: | ||||
|     dependencies: | ||||
|       n8n-workflow: | ||||
|         specifier: '*' | ||||
|         version: 1.48.0 | ||||
|     devDependencies: | ||||
|       '@typescript-eslint/parser': | ||||
|         specifier: ^7.15.0 | ||||
|  | @ -20,9 +24,6 @@ importers: | |||
|       gulp: | ||||
|         specifier: ^4.0.2 | ||||
|         version: 4.0.2 | ||||
|       n8n-workflow: | ||||
|         specifier: '*' | ||||
|         version: 1.48.0 | ||||
|       prettier: | ||||
|         specifier: ^3.3.2 | ||||
|         version: 3.3.2 | ||||
|  | @ -758,7 +759,7 @@ packages: | |||
|     resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} | ||||
|     engines: {node: '>= 4.0'} | ||||
|     os: [darwin] | ||||
|     deprecated: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2 | ||||
|     deprecated: Upgrade to fsevents v2 to mitigate potential security issues | ||||
| 
 | ||||
|   function-bind@1.1.2: | ||||
|     resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue