Skip to main content
Glama
base.tsβ€’8.83 kB
/** * Core list CRUD operations. */ import { getLazyAttioClient } from '../../api/lazy-client.js'; import { getAllLists as getGenericLists, getListDetails as getGenericListDetails, } from '../../api/operations/index.js'; import { EnhancedApiError } from '../../errors/enhanced-api-errors.js'; import { getErrorMessage, getErrorStatus, } from '../../types/error-interfaces.js'; import { hasErrorResponse } from '../../types/list-types.js'; import { createScopedLogger, OperationType } from '../../utils/logger.js'; import type { AttioList } from '../../types/attio.js'; import { asListArray, ensureListShape, extract } from './shared.js'; /** * Gets all lists in the workspace. */ export async function getLists( objectSlug?: string, limit: number = 20 ): Promise<AttioList[]> { try { return await getGenericLists(objectSlug, limit); } catch (error: unknown) { const errorMessage = getErrorMessage(error) ?? 'Unknown error'; if (process.env.NODE_ENV === 'development') { createScopedLogger('objects.lists', 'getLists').warn( 'Generic getLists failed', { errorMessage } ); } const api = getLazyAttioClient(); let path = `/lists?limit=${limit}`; if (objectSlug) { path += `&objectSlug=${objectSlug}`; } const response = await api.get(path); return asListArray(extract<AttioList[]>(response)); } } /** * Gets details for a specific list. */ export async function getListDetails(listId: string): Promise<AttioList> { try { return await getGenericListDetails(listId); } catch (error: unknown) { const errorMessage = getErrorMessage(error) ?? 'Unknown error'; if (process.env.NODE_ENV === 'development') { createScopedLogger('objects.lists', 'getListDetails').warn( 'Generic getListDetails failed', { errorMessage } ); } const api = getLazyAttioClient(); const path = `/lists/${listId}`; try { const response = await api.get(path); const extracted = extract<AttioList>(response); return ensureListShape(extracted); } catch (apiError: unknown) { const status = getErrorStatus(apiError); if (status === 404) { throw new EnhancedApiError('Record not found', 404, path, 'GET', { resourceType: 'lists', recordId: String(listId), httpStatus: 404, documentationHint: 'Use search-lists to find valid list IDs.', }); } if (status === 422) { const { InvalidRequestError } = await import( '../../errors/api-errors.js' ); throw new InvalidRequestError( 'Invalid parameter(s) for list operation', '/lists', 'GET' ); } const code = typeof status === 'number' ? status : 500; throw new EnhancedApiError( getErrorMessage(apiError) ?? 'List retrieval failed', code, path, 'GET', { resourceType: 'lists', recordId: String(listId), httpStatus: code, } ); } } } /** * Creates a new list in Attio. */ export async function createList( attributes: Record<string, unknown> ): Promise<AttioList> { if (!attributes || typeof attributes !== 'object') { throw new Error('Invalid attributes: Must be a non-empty object'); } if (!attributes.name) { throw new Error('List name is required'); } if (!attributes.parent_object) { throw new Error( 'Parent object type is required (e.g., "companies", "people")' ); } const api = getLazyAttioClient(); const path = '/lists'; try { if (process.env.NODE_ENV === 'development') { createScopedLogger( 'objects.lists', 'createList', OperationType.API_CALL ).info('Creating list with attributes', { attributes }); } const response = await api.post(path, { data: attributes, }); if (process.env.NODE_ENV === 'development') { createScopedLogger( 'objects.lists', 'createList', OperationType.API_CALL ).info('Create list success', { data: response.data }); } const extracted = extract<AttioList>(response); return ensureListShape(extracted); } catch (error) { if (process.env.NODE_ENV === 'development') { const log = createScopedLogger('objects.lists', 'createList'); log.warn('Create list error', { message: error instanceof Error ? error.message : 'Unknown error', status: hasErrorResponse(error) ? error.response?.status : undefined, data: hasErrorResponse(error) ? error.response?.data || {} : undefined, }); } if (hasErrorResponse(error) && error.response?.status === 400) { throw new Error( `Invalid list attributes: ${ error instanceof Error ? error.message : 'Bad request' }` ); } else if (hasErrorResponse(error) && error.response?.status === 403) { throw new Error('Insufficient permissions to create list'); } throw error; } } /** * Updates a list in Attio. */ export async function updateList( listId: string, attributes: Record<string, unknown> ): Promise<AttioList> { if (!listId || typeof listId !== 'string') { throw new Error('Invalid list ID: Must be a non-empty string'); } if (!attributes || typeof attributes !== 'object') { throw new Error('Invalid attributes: Must be a non-empty object'); } const api = getLazyAttioClient(); const path = `/lists/${listId}`; try { if (process.env.NODE_ENV === 'development') { createScopedLogger( 'objects.lists', 'updateList', OperationType.API_CALL ).info('Updating list', { listId, attributes, }); } const response = await api.patch(path, { data: attributes, }); if (process.env.NODE_ENV === 'development') { createScopedLogger( 'objects.lists', 'updateList', OperationType.API_CALL ).info('Update list success', { data: response.data }); } return extract<AttioList>(response); } catch (error) { if (process.env.NODE_ENV === 'development') { const log = createScopedLogger('objects.lists', 'updateList'); log.warn('Update list error', { message: error instanceof Error ? error.message : 'Unknown error', status: hasErrorResponse(error) ? error.response?.status : undefined, data: hasErrorResponse(error) ? error.response?.data || {} : undefined, }); } if (hasErrorResponse(error) && error.response?.status === 404) { throw new Error(`List ${listId} not found`); } else if (hasErrorResponse(error) && error.response?.status === 400) { throw new Error( `Invalid list attributes: ${ error instanceof Error ? error.message : 'Bad request' }` ); } else if (hasErrorResponse(error) && error.response?.status === 403) { throw new Error(`Insufficient permissions to update list ${listId}`); } throw error; } } /** * Deletes a list in Attio. */ export async function deleteList(listId: string): Promise<boolean> { if (!listId || typeof listId !== 'string') { throw new Error('Invalid list ID: Must be a non-empty string'); } const api = getLazyAttioClient(); const path = `/lists/${listId}`; try { if (process.env.NODE_ENV === 'development') { createScopedLogger( 'objects.lists', 'deleteList', OperationType.API_CALL ).info('Deleting list', { listId }); } await api.delete(path); if (process.env.NODE_ENV === 'development') { createScopedLogger( 'objects.lists', 'deleteList', OperationType.API_CALL ).info('Delete list success', { listId }); } return true; } catch (error: unknown) { if (process.env.NODE_ENV === 'development') { const log = createScopedLogger('objects.lists', 'deleteList'); log.warn('Delete list error', { message: getErrorMessage(error) ?? 'Unknown error', status: hasErrorResponse(error) ? error.response?.status : undefined, data: hasErrorResponse(error) ? error.response?.data || {} : undefined, }); } const status = getErrorStatus(error); if (status === 404) { throw new EnhancedApiError('Record not found', 404, path, 'DELETE', { resourceType: 'lists', recordId: String(listId), httpStatus: 404, }); } const code = Number.isFinite(status) ? (status as number) : 500; throw new EnhancedApiError( getErrorMessage(error) ?? 'List deletion failed', code, path, 'DELETE', { resourceType: 'lists', recordId: String(listId), httpStatus: code, } ); } }

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