Skip to main content
Glama
task-creator.tsβ€’5.52 kB
/** * TaskCreator - Strategy implementation for task resource creation * * Handles task-specific creation logic by delegating to the existing tasks * object and converting the result to AttioRecord format. */ import type { AttioRecord, JsonObject } from '../../../types/attio.js'; import type { ResourceCreatorContext } from './types.js'; import { BaseCreator } from './base-creator.js'; import { safeExtractRecordId } from '../../../utils/type-extraction.js'; /** * Task-specific resource creator * Implements Strategy Pattern for task creation via delegation */ export class TaskCreator extends BaseCreator { readonly resourceType = 'tasks'; readonly endpoint = '/tasks'; // Lazy-loaded dependencies to prevent resource leaks from repeated dynamic imports private taskModule: JsonObject | null = null; private converterModule: JsonObject | null = null; /** * Lazy-loads task dependencies to prevent repeated dynamic imports */ private async ensureDependencies(): Promise<void> { if (!this.taskModule) { this.taskModule = await import('../../../objects/tasks.js'); } if (!this.converterModule) { this.converterModule = await import('../data-normalizers.js'); } } /** * Creates a task record via delegation to tasks object * * @param input - Task data including content, assigneeId, dueDate, recordId, etc. * @param context - Shared context with client and utilities * @returns Promise<AttioRecord> - Created task record in AttioRecord format */ async create( input: JsonObject, context: ResourceCreatorContext ): Promise<AttioRecord> { context.debug(this.constructor.name, 'πŸ” Task creation input', { content: input.content, assigneeId: input.assigneeId, dueDate: input.dueDate, recordId: input.recordId, targetObject: input.targetObject, } as JsonObject); if (typeof input.content !== 'string' || input.content.trim() === '') { throw this.createEnhancedError( new Error('missing required parameter: content'), context, 400 ); } try { // Ensure dependencies are loaded await this.ensureDependencies(); // Build options object with only defined values to avoid passing "undefined" strings const options: JsonObject = {}; if (input.assigneeId && input.assigneeId !== 'undefined') { options.assigneeId = input.assigneeId as string; } if ( input.dueDate && input.dueDate !== 'undefined' && input.dueDate !== 'null' && typeof input.dueDate === 'string' && input.dueDate.trim() !== '' ) { options.dueDate = input.dueDate as string; } if (input.recordId && input.recordId !== 'undefined') { options.recordId = input.recordId as string; } if (input.targetObject && input.targetObject !== 'undefined') { options.targetObject = input.targetObject as string; } const createTaskFn = (this.taskModule as JsonObject).createTask as ( content: string, options: JsonObject ) => Promise<JsonObject>; const createdTask = await createTaskFn(input.content as string, options); context.debug(this.constructor.name, 'Task creation response', { hasTask: !!createdTask, taskId: createdTask?.id, taskKeys: createdTask ? Object.keys(createdTask) : [], } as JsonObject); // Convert task to AttioRecord format const convertFn = (this.converterModule as JsonObject) .convertTaskToAttioRecord as ( task: JsonObject, input: JsonObject ) => AttioRecord; const record = convertFn(createdTask, input); // Ensure E2E compatibility: include values.assignee when assigneeId provided try { if ( input.assigneeId && (!record.values || !(record.values as JsonObject).assignee) ) { const values: JsonObject = (record.values as JsonObject) || {}; values.assignee = [{ value: input.assigneeId }]; (record as JsonObject).values = values; } } catch { // Ignore conversion errors, maintain compatibility } context.debug(this.constructor.name, 'Converted task record', { recordId: safeExtractRecordId(record), resourceType: record.resource_type, } as JsonObject); return record; } catch (err: unknown) { context.logError(this.constructor.name, 'Task creation error', { error: (err as Error)?.message, input, } as JsonObject); return this.handleApiError(err, context, input); } } /** * Tasks don't require input normalization beyond what's in the input */ protected normalizeInput(input: JsonObject): JsonObject { return input; } /** * Tasks use delegation, so no direct recovery needed * The tasks object handles its own error cases */ protected getRecoveryOptions(): null { return null; } /** * Override attemptRecovery to handle delegation approach */ protected async attemptRecovery( context: ResourceCreatorContext, // eslint-disable-next-line @typescript-eslint/no-unused-vars _normalizedInput?: JsonObject ): Promise<AttioRecord> { // Tasks are handled via delegation, so no direct recovery needed throw this.createEnhancedError( new Error('Task creation failed via delegation - no recovery available'), context, 500 ); } }

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