Skip to main content
Glama
relationship-helpers.tsβ€’4.61 kB
/** * Utility functions for relationship management */ /** * Extracts a single record ID from a team member (string or object) * @param item - Team member that can be string or object * @returns Normalized string ID or empty string if invalid */ export function extractSingleRecordId(item: TeamMember): string { if (typeof item === 'string') { return item; } if (typeof item === 'object' && item !== null) { return item.target_record_id || item.record_id || String(item); } return String(item); } /** * Type representing a team member that can be either a string ID or an object with target_record_id */ export type TeamMember = | string | { target_record_id?: string; record_id?: string; [key: string]: unknown }; /** * Extracts normalized record IDs from team member objects or strings * Handles various formats returned by the Attio API * * @param items - Array of team members (strings or objects) * @returns Array of normalized string IDs, filtered to remove empty values */ export function extractRecordIds(items: Array<TeamMember>): string[] { if (!Array.isArray(items)) { return []; } return items .map((item: TeamMember) => { if (typeof item === 'string') { return item; } // Handle object cases - try multiple possible ID fields if (typeof item === 'object' && item !== null) { return item.target_record_id || item.record_id || String(item); } return String(item); }) .filter(Boolean); // Remove empty/falsy values } /** * Interface representing the state of a bidirectional relationship */ export interface RelationshipState { isInTeam: boolean; isCompanySet: boolean; currentTeamSize: number; needsRepair: boolean; } /** * Analyzes the current state of a company-person relationship * * @param teamIds - Array of person IDs in the company's team * @param personCompany - Company ID set on the person (can be string, object, or null) * @param targetPersonId - The person ID we're checking * @param targetCompanyId - The company ID we're checking * @returns Object describing the relationship state */ export function analyzeRelationshipState( teamIds: string[], personCompany: | string | { target_record_id?: string; record_id?: string } | null, targetPersonId: string, targetCompanyId: string ): RelationshipState { const isInTeam = teamIds.includes(targetPersonId); // Normalize person's company field let personCompanyId: string | null = null; if (typeof personCompany === 'string') { personCompanyId = personCompany; } else if (personCompany && typeof personCompany === 'object') { personCompanyId = personCompany.target_record_id || personCompany.record_id || null; } const isCompanySet = personCompanyId === targetCompanyId; const needsRepair = isInTeam !== isCompanySet; return { isInTeam, isCompanySet, currentTeamSize: teamIds.length, needsRepair, }; } /** * Executes bidirectional update operations with retry logic and partial failure handling * @param operations - Array of async operations to execute * @param maxRetries - Maximum number of retry attempts (default: 2) * @returns Results of all operations */ export async function executeWithRetry<T>( operations: Array<() => Promise<T>>, maxRetries: number = 2 ): Promise<T[]> { const results: T[] = []; const errors: Error[] = []; for (let i = 0; i < operations.length; i++) { const operation = operations[i]; let lastError: Error | null = null; let success = false; // Retry logic for each operation for (let attempt = 0; attempt <= maxRetries; attempt++) { try { const result = await operation(); results[i] = result; success = true; break; } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); // Wait before retry (exponential backoff) if (attempt < maxRetries) { await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 100) ); } } } if (!success && lastError) { errors.push(lastError); } } // If any operations failed, throw detailed error if (errors.length > 0) { const failedCount = errors.length; const successCount = operations.length - failedCount; throw new Error( `Bidirectional update partially failed: ${successCount}/${operations.length} operations succeeded. ` + `Failures: ${errors.map((e) => e.message).join(', ')}` ); } return results; }

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