*/ public static function get_registry(): array { return array( // Triggers. 'scheduleTrigger' => array( 'label' => 'Schedule Trigger', 'icon' => 'symbol', 'symbol' => '⏰', 'color' => '#31C48D', 'bg' => '#1a3a2e', ), 'webhook' => array( 'label' => 'Webhook', 'icon' => 'symbol', 'symbol' => '⇆', 'color' => '#5277D4', 'bg' => '#1a2040', ), 'manualTrigger' => array( 'label' => 'Manual Trigger', 'icon' => 'symbol', 'symbol' => '▶', 'color' => '#FF6B35', 'bg' => '#3a1a00', ), 'formTrigger' => array( 'label' => 'Form Trigger', 'icon' => 'symbol', 'symbol' => '▤', 'color' => '#9B59B6', 'bg' => '#2a1040', ), 'emailReadImap' => array( 'label' => 'Email (IMAP)', 'icon' => 'symbol', 'symbol' => '✉', 'color' => '#E74C3C', 'bg' => '#3a1010', ), 'respondToWebhook' => array( 'label' => 'Respond to Webhook', 'icon' => 'symbol', 'symbol' => '↩', 'color' => '#5277D4', 'bg' => '#1a2040', ), // Core logic. 'code' => array( 'label' => 'Code', 'icon' => 'symbol', 'symbol' => '{ }', 'color' => '#FF9500', 'bg' => '#3a2000', ), 'function' => array( 'label' => 'Function', 'icon' => 'symbol', 'symbol' => 'ƒ', 'color' => '#FF9500', 'bg' => '#3a2000', ), 'executeWorkflow' => array( 'label' => 'Execute Workflow', 'icon' => 'symbol', 'symbol' => '↺', 'color' => '#7F8C8D', 'bg' => '#2d2d2d', ), 'httpRequest' => array( 'label' => 'HTTP Request', 'icon' => 'symbol', 'symbol' => '⊕', 'color' => '#5277D4', 'bg' => '#1a2040', ), 'wait' => array( 'label' => 'Wait', 'icon' => 'symbol', 'symbol' => 'II', 'color' => '#9B59B6', 'bg' => '#2a1040', ), 'if' => array( 'label' => 'If', 'icon' => 'symbol', 'symbol' => '?', 'color' => '#F39C12', 'bg' => '#3a2800', ), 'switch' => array( 'label' => 'Switch', 'icon' => 'symbol', 'symbol' => '⋈', 'color' => '#F39C12', 'bg' => '#3a2800', ), 'merge' => array( 'label' => 'Merge', 'icon' => 'symbol', 'symbol' => '⊕', 'color' => '#26C6DA', 'bg' => '#003040', ), 'splitInBatches' => array( 'label' => 'Split in Batches', 'icon' => 'symbol', 'symbol' => '⋮', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), 'set' => array( 'label' => 'Set', 'icon' => 'symbol', 'symbol' => '=', 'color' => '#26C6DA', 'bg' => '#003040', ), 'editFields' => array( 'label' => 'Edit Fields', 'icon' => 'symbol', 'symbol' => '=', 'color' => '#26C6DA', 'bg' => '#003040', ), 'filter' => array( 'label' => 'Filter', 'icon' => 'symbol', 'symbol' => '▽', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), 'aggregate' => array( 'label' => 'Aggregate', 'icon' => 'symbol', 'symbol' => '∑', 'color' => '#26C6DA', 'bg' => '#003040', ), 'splitOut' => array( 'label' => 'Split Out', 'icon' => 'symbol', 'symbol' => '↔', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), 'sort' => array( 'label' => 'Sort', 'icon' => 'symbol', 'symbol' => '↕', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), 'limit' => array( 'label' => 'Limit', 'icon' => 'symbol', 'symbol' => '⊐', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), 'removeDuplicates' => array( 'label' => 'Remove Duplicates', 'icon' => 'symbol', 'symbol' => '≠', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), 'itemLists' => array( 'label' => 'Item Lists', 'icon' => 'symbol', 'symbol' => '≡', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), 'compareDatasets' => array( 'label' => 'Compare Datasets', 'icon' => 'symbol', 'symbol' => '△', 'color' => '#26C6DA', 'bg' => '#003040', ), 'noOp' => array( 'label' => 'No Operation', 'icon' => 'symbol', 'symbol' => '∅', 'color' => '#BDC3C7', 'bg' => '#2d2d2d', ), 'stickyNote' => array( 'label' => 'Sticky Note', 'icon' => 'symbol', 'symbol' => '📌', 'color' => '#F1C40F', 'bg' => '#3a3000', ), 'stopAndError' => array( 'label' => 'Stop and Error', 'icon' => 'symbol', 'symbol' => '✕', 'color' => '#E74C3C', 'bg' => '#3a1010', ), // Data transformation. 'toFile' => array( 'label' => 'To File', 'icon' => 'symbol', 'symbol' => '↓', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), 'convertToFile' => array( 'label' => 'Convert to File', 'icon' => 'symbol', 'symbol' => '↓', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), 'html' => array( 'label' => 'HTML', 'icon' => 'symbol', 'symbol' => '', 'color' => '#E34F26', 'bg' => '#3a1000', ), 'xml' => array( 'label' => 'XML', 'icon' => 'symbol', 'symbol' => '', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), 'markdown' => array( 'label' => 'Markdown', 'icon' => 'symbol', 'symbol' => 'M↓', 'color' => '#083FA1', 'bg' => '#001040', ), 'crypto' => array( 'label' => 'Crypto', 'icon' => 'symbol', 'symbol' => '🔒', 'color' => '#F39C12', 'bg' => '#3a2800', ), 'compression' => array( 'label' => 'Compression', 'icon' => 'symbol', 'symbol' => '⇩', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), 'extractFromFile' => array( 'label' => 'Extract from File', 'icon' => 'symbol', 'symbol' => '↑', 'color' => '#95A5A6', 'bg' => '#2d2d2d', ), // Databases. 'mySql' => array( 'label' => 'MySQL', 'icon' => 'initials', 'symbol' => 'My', 'color' => '#4479A1', 'bg' => '#001530', ), 'postgres' => array( 'label' => 'PostgreSQL', 'icon' => 'initials', 'symbol' => 'PG', 'color' => '#336791', 'bg' => '#001030', ), 'redis' => array( 'label' => 'Redis', 'icon' => 'initials', 'symbol' => 'Re', 'color' => '#DC382D', 'bg' => '#3a1010', ), 'mongodb' => array( 'label' => 'MongoDB', 'icon' => 'initials', 'symbol' => 'Mg', 'color' => '#4DB33D', 'bg' => '#103010', ), 'sqlite' => array( 'label' => 'SQLite', 'icon' => 'initials', 'symbol' => 'SL', 'color' => '#003B57', 'bg' => '#001020', ), 'microsoftSql' => array( 'label' => 'MS SQL', 'icon' => 'initials', 'symbol' => 'MS', 'color' => '#CC2927', 'bg' => '#3a1010', ), 'supabase' => array( 'label' => 'Supabase', 'icon' => 'initials', 'symbol' => 'Sb', 'color' => '#3ECF8E', 'bg' => '#103020', ), // Communication. 'slack' => array( 'label' => 'Slack', 'icon' => 'initials', 'symbol' => 'Sl', 'color' => '#4A154B', 'bg' => '#200020', ), 'telegram' => array( 'label' => 'Telegram', 'icon' => 'symbol', 'symbol' => '✈', 'color' => '#2CA5E0', 'bg' => '#003040', ), 'discord' => array( 'label' => 'Discord', 'icon' => 'initials', 'symbol' => 'Dc', 'color' => '#5865F2', 'bg' => '#101080', ), 'mattermost' => array( 'label' => 'Mattermost', 'icon' => 'initials', 'symbol' => 'Mm', 'color' => '#0058CC', 'bg' => '#001840', ), 'emailSend' => array( 'label' => 'Send Email', 'icon' => 'symbol', 'symbol' => '✉', 'color' => '#E74C3C', 'bg' => '#3a1010', ), 'sendEmail' => array( 'label' => 'Send Email', 'icon' => 'symbol', 'symbol' => '✉', 'color' => '#E74C3C', 'bg' => '#3a1010', ), 'gmail' => array( 'label' => 'Gmail', 'icon' => 'initials', 'symbol' => 'Gm', 'color' => '#EA4335', 'bg' => '#3a1010', ), 'microsoftOutlook' => array( 'label' => 'Outlook', 'icon' => 'initials', 'symbol' => 'Ol', 'color' => '#0078D4', 'bg' => '#001840', ), 'whatsapp' => array( 'label' => 'WhatsApp', 'icon' => 'initials', 'symbol' => 'WA', 'color' => '#25D366', 'bg' => '#103020', ), 'twilio' => array( 'label' => 'Twilio', 'icon' => 'initials', 'symbol' => 'Tw', 'color' => '#F22F46', 'bg' => '#3a1010', ), // Google. 'googleSheets' => array( 'label' => 'Google Sheets', 'icon' => 'initials', 'symbol' => 'GS', 'color' => '#34A853', 'bg' => '#103020', ), 'googleDrive' => array( 'label' => 'Google Drive', 'icon' => 'initials', 'symbol' => 'GD', 'color' => '#4285F4', 'bg' => '#001840', ), 'googleCalendar' => array( 'label' => 'Google Calendar', 'icon' => 'initials', 'symbol' => 'GC', 'color' => '#4285F4', 'bg' => '#001840', ), 'googleDocs' => array( 'label' => 'Google Docs', 'icon' => 'initials', 'symbol' => 'Gd', 'color' => '#4285F4', 'bg' => '#001840', ), 'youTube' => array( 'label' => 'YouTube', 'icon' => 'initials', 'symbol' => 'YT', 'color' => '#FF0000', 'bg' => '#3a0000', ), // Dev / Version control. 'github' => array( 'label' => 'GitHub', 'icon' => 'initials', 'symbol' => 'GH', 'color' => '#24292E', 'bg' => '#000000', ), 'gitlab' => array( 'label' => 'GitLab', 'icon' => 'initials', 'symbol' => 'GL', 'color' => '#FC6D26', 'bg' => '#3a1a00', ), 'jira' => array( 'label' => 'Jira', 'icon' => 'initials', 'symbol' => 'Ji', 'color' => '#0052CC', 'bg' => '#001840', ), 'confluence' => array( 'label' => 'Confluence', 'icon' => 'initials', 'symbol' => 'Cf', 'color' => '#0052CC', 'bg' => '#001840', ), 'linear' => array( 'label' => 'Linear', 'icon' => 'initials', 'symbol' => 'Li', 'color' => '#5E6AD2', 'bg' => '#101040', ), 'notion' => array( 'label' => 'Notion', 'icon' => 'initials', 'symbol' => 'No', 'color' => '#FFFFFF', 'bg' => '#1a1a1a', ), // AI. 'openAi' => array( 'label' => 'OpenAI', 'icon' => 'initials', 'symbol' => 'OA', 'color' => '#00A67E', 'bg' => '#003020', ), 'anthropicClaude' => array( 'label' => 'Anthropic', 'icon' => 'initials', 'symbol' => 'An', 'color' => '#D97757', 'bg' => '#3a1a00', ), 'anthropic' => array( 'label' => 'Anthropic', 'icon' => 'initials', 'symbol' => 'An', 'color' => '#D97757', 'bg' => '#3a1a00', ), 'gemini' => array( 'label' => 'Gemini', 'icon' => 'initials', 'symbol' => 'Gm', 'color' => '#4285F4', 'bg' => '#001840', ), 'googleAi' => array( 'label' => 'Google AI', 'icon' => 'initials', 'symbol' => 'GA', 'color' => '#4285F4', 'bg' => '#001840', ), 'huggingFace' => array( 'label' => 'HuggingFace', 'icon' => 'initials', 'symbol' => 'HF', 'color' => '#FFD21E', 'bg' => '#3a2a00', ), 'mistral' => array( 'label' => 'Mistral', 'icon' => 'initials', 'symbol' => 'Mi', 'color' => '#FF7000', 'bg' => '#3a1a00', ), 'ollama' => array( 'label' => 'Ollama', 'icon' => 'initials', 'symbol' => 'Ol', 'color' => '#7C3AED', 'bg' => '#200040', ), 'lmChatOllama' => array( 'label' => 'Ollama Chat', 'icon' => 'initials', 'symbol' => 'Ol', 'color' => '#7C3AED', 'bg' => '#200040', ), 'cohere' => array( 'label' => 'Cohere', 'icon' => 'initials', 'symbol' => 'Co', 'color' => '#39594D', 'bg' => '#102020', ), 'lmChatOpenAi' => array( 'label' => 'OpenAI Chat', 'icon' => 'initials', 'symbol' => 'OA', 'color' => '#00A67E', 'bg' => '#003020', ), 'lmChatAnthropic' => array( 'label' => 'Anthropic Chat', 'icon' => 'initials', 'symbol' => 'An', 'color' => '#D97757', 'bg' => '#3a1a00', ), 'agent' => array( 'label' => 'AI Agent', 'icon' => 'symbol', 'symbol' => '🤖', 'color' => '#7C3AED', 'bg' => '#200040', ), 'chainLlm' => array( 'label' => 'LLM Chain', 'icon' => 'symbol', 'symbol' => '⛓', 'color' => '#7C3AED', 'bg' => '#200040', ), 'vectorStore' => array( 'label' => 'Vector Store', 'icon' => 'symbol', 'symbol' => '⊞', 'color' => '#7C3AED', 'bg' => '#200040', ), 'memoryBufferWindow' => array( 'label' => 'Memory Buffer', 'icon' => 'symbol', 'symbol' => '◫', 'color' => '#7C3AED', 'bg' => '#200040', ), // Storage / Files. 'ftp' => array( 'label' => 'FTP', 'icon' => 'initials', 'symbol' => 'FT', 'color' => '#F39C12', 'bg' => '#3a2800', ), 'ssh' => array( 'label' => 'SSH', 'icon' => 'symbol', 'symbol' => '$_', 'color' => '#2ECC71', 'bg' => '#103020', ), 'readWriteFile' => array( 'label' => 'Read/Write Files', 'icon' => 'symbol', 'symbol' => '📁', 'color' => '#F39C12', 'bg' => '#3a2800', ), 'airtable' => array( 'label' => 'Airtable', 'icon' => 'initials', 'symbol' => 'At', 'color' => '#18BFFF', 'bg' => '#003040', ), 'baserow' => array( 'label' => 'Baserow', 'icon' => 'initials', 'symbol' => 'Br', 'color' => '#4A90D9', 'bg' => '#001840', ), // CRM / Marketing. 'hubspot' => array( 'label' => 'HubSpot', 'icon' => 'initials', 'symbol' => 'Hs', 'color' => '#FF7A59', 'bg' => '#3a1a00', ), 'salesforce' => array( 'label' => 'Salesforce', 'icon' => 'initials', 'symbol' => 'Sf', 'color' => '#00A1E0', 'bg' => '#003040', ), 'mailchimp' => array( 'label' => 'Mailchimp', 'icon' => 'initials', 'symbol' => 'Mc', 'color' => '#FFE01B', 'bg' => '#3a3000', ), 'brevo' => array( 'label' => 'Brevo', 'icon' => 'initials', 'symbol' => 'Bv', 'color' => '#0092FF', 'bg' => '#003040', ), // WordPress / CMS. 'wordpress' => array( 'label' => 'WordPress', 'icon' => 'initials', 'symbol' => 'WP', 'color' => '#21759B', 'bg' => '#002030', ), 'rssFeedRead' => array( 'label' => 'RSS Feed', 'icon' => 'symbol', 'symbol' => '◉', 'color' => '#F26522', 'bg' => '#3a1000', ), ); } /** * Looks up a node by its full n8n type string. * Extracts the slug (last segment after dot) for registry lookup. * * @param string $type Full n8n type string e.g. "n8n-nodes-base.httpRequest". * @return array Node type data or fallback entry. */ public static function lookup( string $type ): array { $registry = self::get_registry(); $slug = self::extract_slug( $type ); // Case-sensitive exact match first. if ( isset( $registry[ $slug ] ) ) { return $registry[ $slug ]; } // Case-insensitive fallback. $slug_lower = strtolower( $slug ); foreach ( $registry as $key => $entry ) { if ( strtolower( $key ) === $slug_lower ) { return $entry; } } // Generate fallback entry. return self::generate_fallback( $type, $slug ); } /** * Extracts the node slug from a full n8n type string. * * @param string $type e.g. "n8n-nodes-base.httpRequest" → "httpRequest". */ public static function extract_slug( string $type ): string { $parts = explode( '.', $type ); return end( $parts ); } /** * Generates a deterministic fallback entry for unknown node types. * Uses djb2 hash for a consistent color. * * @since 1.0.0 * @param string $type Full n8n node type string. * @param string $slug Extracted slug portion. * @return array Fallback display metadata. */ private static function generate_fallback( string $type, string $slug ): array { $hue = self::djb2_color_hue( $type ); $hex = self::hsl_to_hex( $hue, 60, 55 ); $bg = self::hsl_to_hex( $hue, 40, 15 ); // Derive 2-letter initials from slug. $initials = self::derive_initials( $slug ); return array( 'label' => $slug, 'icon' => 'initials', 'symbol' => $initials, 'color' => $hex, 'bg' => $bg, ); } /** * Derives 2-letter initials from a camelCase or PascalCase slug. * * @since 1.0.0 * @param string $slug Node type slug. * @return string Two uppercase initials. */ private static function derive_initials( string $slug ): string { // Split on camelCase boundaries. $parts = preg_split( '/(?=[A-Z])/', $slug, -1, PREG_SPLIT_NO_EMPTY ); if ( ! $parts ) { return strtoupper( substr( $slug, 0, 2 ) ); } if ( count( $parts ) >= 2 ) { return strtoupper( substr( $parts[0], 0, 1 ) . substr( $parts[1], 0, 1 ) ); } return strtoupper( substr( $slug, 0, 2 ) ); } /** * Computes a djb2 hash and maps it to a color hue in the 0-359 range. * * @since 1.0.0 * @param string $str Input string to hash. * @return int Hue value between 0 and 359. */ private static function djb2_color_hue( string $str ): int { $hash = 5381; $len = strlen( $str ); for ( $i = 0; $i < $len; $i++ ) { $hash = ( ( $hash << 5 ) + $hash ) + ord( $str[ $i ] ); $hash &= 0xFFFFFFFF; } return abs( $hash ) % 360; } /** * Converts HSL to 6-digit hex color string. * * @since 1.0.0 * @param int $h Hue (0-359). * @param int $s Saturation (0-100). * @param int $l Lightness (0-100). * @return string Hex color string (e.g. "#ff8800"). */ private static function hsl_to_hex( int $h, int $s, int $l ): string { $s /= 100; $l /= 100; $a = $s * min( $l, 1 - $l ); $f = static function ( $n ) use ( $h, $l, $a ) { $k = fmod( $n + $h / 30, 12 ); return $l - $a * max( min( $k - 3, 9 - $k, 1 ), -1 ); }; $r = (int) round( $f( 0 ) * 255 ); $g = (int) round( $f( 8 ) * 255 ); $b = (int) round( $f( 4 ) * 255 ); return sprintf( '#%02x%02x%02x', max( 0, min( 255, $r ) ), max( 0, min( 255, $g ) ), max( 0, min( 255, $b ) ) ); } }