import { isNonEmptyString } from '@sniptt/guards'; import { CoreApiClient } from 'twenty-client-sdk/core'; import { defineLogicFunction } from 'twenty-sdk/define'; import { GRANOLA_CONNECTION_LOGIC_FUNCTIONS } from 'src/constants/universal-identifiers'; import { upsertConnection } from 'src/logic-functions/utils/granola-connection-store'; import { resolveWorkspaceMember } from 'src/logic-functions/utils/resolve-workspace-member'; import { validateGranolaKey } from 'src/logic-functions/utils/validate-granola-key'; type SetKeyInput = { body?: { apiKey?: unknown } | null } | undefined; type SetKeyResult = { success: boolean; message?: string }; const handler = async (input: SetKeyInput): Promise => { const rawApiKey = input?.body?.apiKey; const apiKey = typeof rawApiKey === 'string' ? rawApiKey.trim() : ''; if (!isNonEmptyString(apiKey)) { return { success: false, message: 'Enter your Granola API key.' }; } const client = new CoreApiClient(); const member = await resolveWorkspaceMember(client); if (!member) { return { success: false, message: 'Could not identify your account. Please sign in and try again.', }; } const validation = await validateGranolaKey(apiKey); if (!validation.valid) { return { success: false, message: validation.message }; } await upsertConnection({ workspaceMemberId: member.workspaceMemberId, displayName: member.displayName, apiKey, }); return { success: true, message: 'Granola connected. Your meetings will start syncing shortly.', }; }; export default defineLogicFunction({ universalIdentifier: GRANOLA_CONNECTION_LOGIC_FUNCTIONS.setKey.universalIdentifier, name: 'granola-set-key', description: "Stores the invoking member's personal Granola API key after validating it against the Granola API.", timeoutSeconds: 60, handler, httpRouteTriggerSettings: { path: GRANOLA_CONNECTION_LOGIC_FUNCTIONS.setKey.path, httpMethod: 'POST', isAuthRequired: true, }, });