Skip to main content
Glama
attribute-metadata.ts2.73 kB
import type { AttioAttributeMetadata } from '@/api/attribute-types.js'; export type AttributeMetadata = AttioAttributeMetadata & Record<string, unknown>; export type AttributeMetadataIndex = Record<string, AttributeMetadata>; const ATTRIBUTE_KEY_CANDIDATES = [ 'api_slug', 'attribute_slug', 'slug', 'title', 'name', 'label', ]; const FIELD_TYPE_CANDIDATES = [ 'field_type', 'attribute_type', 'type', 'input_type', ]; function normalizeKey(key: string): string { return key.trim().toLowerCase(); } function addKey( index: AttributeMetadataIndex, key: string, metadata: AttributeMetadata ): void { const variants = createLookupKeys(key); variants.forEach((variant) => { index[variant] = metadata; }); } function createLookupKeys(key: string): string[] { const normalized = normalizeKey(key); if (!normalized) return []; const underscored = normalized.replace(/[\s.-]+/g, '_'); if (underscored === normalized) { return [normalized]; } return [normalized, underscored]; } export function buildAttributeMetadataIndex( attributes: unknown[] ): AttributeMetadataIndex { const index: AttributeMetadataIndex = {}; attributes.forEach((attribute) => { if (!attribute || typeof attribute !== 'object') { return; } const metadata = attribute as AttributeMetadata; ATTRIBUTE_KEY_CANDIDATES.forEach((candidate) => { const value = metadata[candidate]; if (typeof value === 'string' && value.trim().length > 0) { addKey(index, value, metadata); } }); }); return index; } export function findAttributeMetadata( field: string, index?: AttributeMetadataIndex ): AttributeMetadata | undefined { if (!index || !field) { return undefined; } const variants = createLookupKeys(field); for (const variant of variants) { if (variant in index) { return index[variant]; } } return undefined; } export function resolveFieldType( metadata?: AttributeMetadata ): string | undefined { if (!metadata) return undefined; const directType = FIELD_TYPE_CANDIDATES.find((candidate) => { const value = metadata[candidate]; return typeof value === 'string' && value.trim().length > 0; }); if (directType) { return String(metadata[directType]).trim(); } const configType = metadata?.config as Record<string, unknown> | undefined; if (configType && typeof configType === 'object') { const nestedType = FIELD_TYPE_CANDIDATES.find((candidate) => { const value = configType[candidate]; return typeof value === 'string' && value.trim().length > 0; }); if (nestedType) { return String(configType[nestedType]).trim(); } } return undefined; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kesslerio/attio-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server