UNPKG

@cryptodevops/n8n-nodes-santiment

Version:
417 lines (416 loc) 18.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Santiment = void 0; const n8n_workflow_1 = require("n8n-workflow"); const axios_1 = __importDefault(require("axios")); const date_utils_1 = require("../../date-utils"); class Santiment { constructor() { this.description = { displayName: 'Santiment', name: 'santiment', icon: 'file:santiment.svg', group: ['input'], version: 1, subtitle: '={{$parameter["operation"]}}', description: 'Interact with Santiment cryptocurrency data API', defaults: { name: 'Santiment', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'santimentApi', required: true, }, ], properties: [ { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, options: [ { name: 'Execute Custom Query', value: 'executeCustomQuery', description: 'Execute a custom GraphQL query', action: 'Execute custom query', }, { name: 'Get Development Activity', value: 'getDevActivity', description: 'Get development activity metrics', action: 'Get development activity', }, { name: 'Get On-Chain Data', value: 'getOnChainData', description: 'Get on-chain metrics', action: 'Get on chain data', }, { name: 'Get Price Data', value: 'getPriceData', description: 'Get price data for cryptocurrencies', action: 'Get price data', }, { name: 'Get Project List', value: 'getProjectList', description: 'Get list of available projects', action: 'Get project list', }, { name: 'Get Sentiment Index', value: 'getSentimentIndex', description: 'Get sentiment analysis metrics', action: 'Get sentiment index', }, { name: 'Get Social Volume', value: 'getSocialVolume', description: 'Get social volume metrics', action: 'Get social volume', }, ], default: 'getPriceData', }, // Paramètres pour l'opération getPriceData { displayName: 'Project Slug', name: 'slug', type: 'string', default: 'bitcoin', required: true, description: 'Slug of the project (e.g., bitcoin, ethereum)', displayOptions: { show: { operation: ['getPriceData', 'getDevActivity', 'getSocialVolume', 'getOnChainData', 'getSentimentIndex'], }, }, }, { displayName: 'From Date', name: 'fromDate', type: 'string', default: 'utc_now-30d', description: 'Start date (format: YYYY-MM-DD ou utc_now-30d). Les formats simples comme YYYY-MM-DD seront automatiquement convertis au format ISO requis par l\'API.', displayOptions: { show: { operation: ['getPriceData', 'getDevActivity', 'getSocialVolume', 'getOnChainData', 'getSentimentIndex'], }, }, }, { displayName: 'To Date', name: 'toDate', type: 'string', default: 'utc_now', description: 'End date (format: YYYY-MM-DD ou utc_now). Les formats simples comme YYYY-MM-DD seront automatiquement convertis au format ISO requis par l\'API.', displayOptions: { show: { operation: ['getPriceData', 'getDevActivity', 'getSocialVolume', 'getOnChainData', 'getSentimentIndex'], }, }, }, { displayName: 'Interval', name: 'interval', type: 'options', options: [ { name: '1 Day', value: '1d' }, { name: '1 Hour', value: '1h' }, { name: '1 Week', value: '1w' }, { name: '15 Minutes', value: '15m' }, { name: '30 Minutes', value: '30m' }, { name: '4 Hours', value: '4h' }, { name: '5 Minutes', value: '5m' }, ], default: '1d', description: 'Time interval between data points', displayOptions: { show: { operation: ['getPriceData', 'getDevActivity', 'getSocialVolume', 'getOnChainData', 'getSentimentIndex'], }, }, }, // Paramètres pour l'opération getSentimentIndex { displayName: 'Sentiment Type', name: 'sentimentType', type: 'options', options: [ { name: 'Sentiment Balance (Total)', value: 'sentiment_balance_total' }, { name: 'Sentiment Positive (Total)', value: 'sentiment_positive_total' }, { name: 'Sentiment Negative (Total)', value: 'sentiment_negative_total' }, ], default: 'sentiment_balance_total', description: 'Type of sentiment metric to retrieve', displayOptions: { show: { operation: ['getSentimentIndex'], }, }, }, // Paramètres pour l'opération getProjectList { displayName: 'Page', name: 'page', type: 'number', default: 1, description: 'Page number for pagination', displayOptions: { show: { operation: ['getProjectList'], }, }, }, { displayName: 'Page Size', name: 'pageSize', type: 'number', default: 20, description: 'Number of projects per page', displayOptions: { show: { operation: ['getProjectList'], }, }, }, // Paramètres pour l'opération executeCustomQuery { displayName: 'GraphQL Query', name: 'query', type: 'string', typeOptions: { rows: 10, }, default: '', placeholder: `{ getMetric(metric: "price_usd") { timeseriesDataJson( slug: "bitcoin" from: "utc_now-30d" to: "utc_now" interval: "1d" ) } }`, description: 'Custom GraphQL query to execute', required: true, displayOptions: { show: { operation: ['executeCustomQuery'], }, }, }, ], }; } async execute() { const items = this.getInputData(); const returnData = []; const credentials = await this.getCredentials('santimentApi'); const apiKey = credentials.apiKey; const operation = this.getNodeParameter('operation', 0); for (let i = 0; i < items.length; i++) { try { let responseData; let query = ''; let variables = {}; switch (operation) { case 'getPriceData': { const slug = this.getNodeParameter('slug', i); const fromDateRaw = this.getNodeParameter('fromDate', i); const toDateRaw = this.getNodeParameter('toDate', i); const interval = this.getNodeParameter('interval', i); // Convertir les dates au format accepté par Santiment const fromDate = (0, date_utils_1.convertToSantimentFormat)(fromDateRaw, false); const toDate = (0, date_utils_1.convertToSantimentFormat)(toDateRaw, true); query = `{ getMetric(metric: "price_usd") { timeseriesDataJson( slug: "${slug}" from: "${fromDate}" to: "${toDate}" interval: "${interval}" ) } }`; break; } case 'getDevActivity': { const slug = this.getNodeParameter('slug', i); const fromDateRaw = this.getNodeParameter('fromDate', i); const toDateRaw = this.getNodeParameter('toDate', i); const interval = this.getNodeParameter('interval', i); // Convertir les dates au format accepté par Santiment const fromDate = (0, date_utils_1.convertToSantimentFormat)(fromDateRaw, false); const toDate = (0, date_utils_1.convertToSantimentFormat)(toDateRaw, true); query = `{ getMetric(metric: "dev_activity") { timeseriesDataJson( slug: "${slug}" from: "${fromDate}" to: "${toDate}" interval: "${interval}" ) } }`; break; } case 'getSentimentIndex': { const slug = this.getNodeParameter('slug', i); const fromDateRaw = this.getNodeParameter('fromDate', i); const toDateRaw = this.getNodeParameter('toDate', i); const interval = this.getNodeParameter('interval', i); const sentimentType = this.getNodeParameter('sentimentType', i); // Convertir les dates au format accepté par Santiment const fromDate = (0, date_utils_1.convertToSantimentFormat)(fromDateRaw, false); const toDate = (0, date_utils_1.convertToSantimentFormat)(toDateRaw, true); query = `{ getMetric(metric: "${sentimentType}") { timeseriesDataJson( slug: "${slug}" from: "${fromDate}" to: "${toDate}" interval: "${interval}" ) } }`; break; } case 'getSocialVolume': { const slug = this.getNodeParameter('slug', i); const fromDateRaw = this.getNodeParameter('fromDate', i); const toDateRaw = this.getNodeParameter('toDate', i); const interval = this.getNodeParameter('interval', i); // Convertir les dates au format accepté par Santiment const fromDate = (0, date_utils_1.convertToSantimentFormat)(fromDateRaw, false); const toDate = (0, date_utils_1.convertToSantimentFormat)(toDateRaw, true); query = `{ getMetric(metric: "social_volume_total") { timeseriesDataJson( slug: "${slug}" from: "${fromDate}" to: "${toDate}" interval: "${interval}" ) } }`; break; } case 'getOnChainData': { const slug = this.getNodeParameter('slug', i); const fromDateRaw = this.getNodeParameter('fromDate', i); const toDateRaw = this.getNodeParameter('toDate', i); const interval = this.getNodeParameter('interval', i); // Convertir les dates au format accepté par Santiment const fromDate = (0, date_utils_1.convertToSantimentFormat)(fromDateRaw, false); const toDate = (0, date_utils_1.convertToSantimentFormat)(toDateRaw, true); query = `{ getMetric(metric: "daily_active_addresses") { timeseriesDataJson( slug: "${slug}" from: "${fromDate}" to: "${toDate}" interval: "${interval}" ) } }`; break; } case 'getProjectList': { const page = this.getNodeParameter('page', i); const pageSize = this.getNodeParameter('pageSize', i); query = `{ allProjects(page: ${page}, pageSize: ${pageSize}) { slug name ticker description logoUrl websiteLink twitterLink marketSegments } }`; break; } case 'executeCustomQuery': { query = this.getNodeParameter('query', i); break; } default: throw new n8n_workflow_1.NodeOperationError(this.getNode(), `L'opération ${operation} n'est pas prise en charge!`); } // Exécuter la requête GraphQL const response = await axios_1.default.post('https://api.santiment.net/graphql', { query, variables }, { headers: { 'Content-Type': 'application/json', Authorization: `Apikey ${apiKey}`, }, }); // Vérifier les erreurs dans la réponse GraphQL if (response.data.errors) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Erreur GraphQL: ${response.data.errors[0].message}`, { itemIndex: i }); } responseData = response.data.data; // Traitement spécifique pour certaines opérations if (['getPriceData', 'getDevActivity', 'getSocialVolume', 'getOnChainData', 'getSentimentIndex'].includes(operation)) { // Convertir la chaîne JSON en objet pour les données de séries temporelles const metricNameMap = { getPriceData: 'price_usd', getDevActivity: 'dev_activity', getSocialVolume: 'social_volume_total', getOnChainData: 'daily_active_addresses', getSentimentIndex: this.getNodeParameter('sentimentType', i), }; const metricName = metricNameMap[operation]; // Vérifier si les données sont vides ou déjà un tableau let timeseriesData; if (responseData.getMetric.timeseriesDataJson === '[]' || responseData.getMetric.timeseriesDataJson === '' || Array.isArray(responseData.getMetric.timeseriesDataJson)) { // Si c'est un tableau vide ou déjà un objet tableau, l'utiliser directement timeseriesData = Array.isArray(responseData.getMetric.timeseriesDataJson) ? responseData.getMetric.timeseriesDataJson : []; } else { try { timeseriesData = JSON.parse(responseData.getMetric.timeseriesDataJson); } catch (parseError) { // En cas d'erreur de parsing, retourner un tableau vide console.error('Erreur de parsing JSON:', parseError.message); timeseriesData = []; } } responseData = { metric: metricName, data: timeseriesData, }; } // Pour les autres opérations (getProjectList et executeCustomQuery), on utilise directement responseData const executionData = this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray(responseData), { itemData: { item: i } }); returnData.push(...executionData); } catch (error) { if (this.continueOnFail()) { const executionErrorData = this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray({ error: error.message }), { itemData: { item: i } }); returnData.push(...executionErrorData); continue; } throw error; } } return [returnData]; } } exports.Santiment = Santiment;