4
package-lock.json
generated
4
package-lock.json
generated
@@ -8943,7 +8943,6 @@
|
||||
"version": "16.12.0",
|
||||
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz",
|
||||
"integrity": "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
|
||||
@@ -15554,6 +15553,9 @@
|
||||
"name": "@probo/n8n-nodes-probo",
|
||||
"version": "0.0.1",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"graphql": "^16.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@n8n/node-cli": "^0.17.0",
|
||||
"eslint": "9.32.0"
|
||||
|
||||
19
packages/n8n-node/nodes/Probo/Probo.node.json
Normal file
19
packages/n8n-node/nodes/Probo/Probo.node.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"node": "n8n-nodes-probo",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Development", "Developer Tools", "Automation"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://www.getprobo.com/docs"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://www.getprobo.com/docs"
|
||||
}
|
||||
],
|
||||
"generic": []
|
||||
}
|
||||
}
|
||||
117
packages/n8n-node/nodes/Probo/Probo.node.ts
Normal file
117
packages/n8n-node/nodes/Probo/Probo.node.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import {
|
||||
NodeConnectionTypes,
|
||||
type IExecuteFunctions,
|
||||
type INodeExecutionData,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
import { executeOperation } from './operations';
|
||||
|
||||
export class Probo implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Probo',
|
||||
name: 'probo',
|
||||
icon: { light: 'file:../../icons/probo.svg', dark: 'file:../../icons/probo.svg' },
|
||||
group: ['input'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"]}}',
|
||||
description: 'Consume data from the Probo API',
|
||||
defaults: {
|
||||
name: 'Probo',
|
||||
},
|
||||
usableAsTool: true,
|
||||
inputs: [NodeConnectionTypes.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
name: 'proboApi',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
authentication: ['apiKey'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
requestDefaults: {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'API Key',
|
||||
value: 'apiKey',
|
||||
},
|
||||
],
|
||||
default: 'apiKey',
|
||||
},
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Execute',
|
||||
value: 'execute',
|
||||
description: 'Execute a GraphQL query or mutation',
|
||||
action: 'Execute a GraphQL operation',
|
||||
},
|
||||
],
|
||||
default: 'execute',
|
||||
},
|
||||
{
|
||||
displayName: 'Query',
|
||||
name: 'query',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
rows: 5,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['execute'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'The complete GraphQL operation including operation name and variable declarations (e.g., "query GetUser($userId: ID!) { node(id: $userId) { id } }" or "mutation UpdateUser($input: UpdateUserInput!) { updateUser(input: $input) { id } }")',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Variables',
|
||||
name: 'variables',
|
||||
type: 'json',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['execute'],
|
||||
},
|
||||
},
|
||||
default: '{}',
|
||||
description: 'GraphQL variables as JSON object',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const operation = this.getNodeParameter('operation', i) as string;
|
||||
const result = await executeOperation.call(this, operation, i);
|
||||
returnData.push(result);
|
||||
}
|
||||
|
||||
return [returnData];
|
||||
}
|
||||
|
||||
methods = {
|
||||
listSearch: {},
|
||||
};
|
||||
}
|
||||
81
packages/n8n-node/nodes/Probo/operations/execute.ts
Normal file
81
packages/n8n-node/nodes/Probo/operations/execute.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { parse, getOperationAST, type DocumentNode } from 'graphql';
|
||||
import type { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
|
||||
|
||||
export interface GraphQLParameters {
|
||||
query: string;
|
||||
variables?: string;
|
||||
}
|
||||
|
||||
export async function executeGraphQL(
|
||||
this: IExecuteFunctions,
|
||||
itemIndex: number,
|
||||
): Promise<INodeExecutionData> {
|
||||
const query = this.getNodeParameter('query', itemIndex) as string;
|
||||
const variablesParam = this.getNodeParameter('variables', itemIndex) as string;
|
||||
|
||||
let document: DocumentNode;
|
||||
try {
|
||||
document = parse(query);
|
||||
} catch (error) {
|
||||
throw new Error(`Invalid GraphQL operation: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
|
||||
const operationAST = getOperationAST(document);
|
||||
if (!operationAST) {
|
||||
throw new Error('GraphQL operation must contain a query, mutation, or subscription');
|
||||
}
|
||||
|
||||
if (!operationAST.name) {
|
||||
throw new Error('GraphQL operation must have a name (e.g., "query GetUser { ... }" or "mutation UpdateUser { ... }")');
|
||||
}
|
||||
|
||||
const operationName = operationAST.name.value;
|
||||
|
||||
let variables = {};
|
||||
if (variablesParam) {
|
||||
try {
|
||||
variables =
|
||||
typeof variablesParam === 'string' ? JSON.parse(variablesParam) : variablesParam;
|
||||
} catch (error) {
|
||||
throw new Error(`Invalid JSON in Variables: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
const body: {
|
||||
query: string;
|
||||
operationName?: string;
|
||||
variables?: Record<string, any>;
|
||||
} = {
|
||||
query,
|
||||
operationName,
|
||||
};
|
||||
|
||||
if (Object.keys(variables).length > 0) {
|
||||
body.variables = variables;
|
||||
}
|
||||
|
||||
const credentials = await this.getCredentials('proboApi');
|
||||
|
||||
if (!credentials!.apiKey) {
|
||||
throw new Error('API Key is required');
|
||||
}
|
||||
|
||||
const responseData = await this.helpers.httpRequest({
|
||||
method: 'POST',
|
||||
baseURL: `${credentials!.server}`,
|
||||
url: '/api/console/v1/query',
|
||||
headers: {
|
||||
Authorization: `Bearer ${credentials!.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: body,
|
||||
json: true,
|
||||
returnFullResponse: true,
|
||||
});
|
||||
|
||||
return {
|
||||
json: responseData,
|
||||
pairedItem: { item: itemIndex },
|
||||
};
|
||||
}
|
||||
|
||||
16
packages/n8n-node/nodes/Probo/operations/index.ts
Normal file
16
packages/n8n-node/nodes/Probo/operations/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
|
||||
import { executeGraphQL } from './execute';
|
||||
|
||||
export async function executeOperation(
|
||||
this: IExecuteFunctions,
|
||||
operation: string,
|
||||
itemIndex: number,
|
||||
): Promise<INodeExecutionData> {
|
||||
switch (operation) {
|
||||
case 'execute':
|
||||
return executeGraphQL.call(this, itemIndex);
|
||||
default:
|
||||
throw new Error(`Unknown operation: ${operation}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,5 +31,8 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"n8n-workflow": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"graphql": "^16.12.0"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user