import {createLogEvent} from '@fudge-ai/javascript/dist/console' import {ErrorStackParser} from '@fudge-ai/javascript/dist/utils/errorStackParser' import {headerNames} from '@fudge-ai/javascript/dist/utils/fetchCapture' import {fudgeLog} from '@fudge-ai/javascript/dist/utils/fudgeLog' import {patch} from '@fudge-ai/javascript/dist/utils/patch' import {FudgeContext, getLastValue} from '@fudge-ai/utils' import {ErrorEvent, FudgeEventType} from '@fudge-ai/utils/dist/events' import type {NextApiHandler, NextApiRequest, NextApiResponse} from 'next' import {serializeError} from 'serialize-error' import {createContext} from './context' import {postEvent, waitForPendingEvents} from './transporter' import {nanoid} from 'nanoid' const context = createContext() export function withFudge(originalHandler: NextApiHandler): NextApiHandler { return async function (req: NextApiRequest, res: NextApiResponse) { const resEndPromise = {current: null as Promise | null} patch(res, 'end', (original) => { return function (...args) { fudgeLog.info('Calling res.end') resEndPromise.current = waitForPendingEvents().then(() => { original(...(args as any)) }) return res } as NextApiResponse['end'] }) await context.runAndReturn(async function () { const connectionId = getLastValue(req.headers[headerNames.connectionId]) const sessionId = getLastValue(req.headers[headerNames.sessionId]) const traceId = getLastValue(req.headers[headerNames.traceId]) if (!connectionId) { fudgeLog.warn('Missing header', headerNames.connectionId) } else { const fudgeContext: FudgeContext = { connectionId, sessionId, traceId, } context.set('fudgeContext', fudgeContext) } context.set('req', req) context.set('res', res) fudgeLog.info('withFudge called', context.get('fudgeContext')) try { await originalHandler(req, res) } catch (error) { fudgeLog.info('Handler threw... (TODO: capture error)') const parsedError = serializeError(error) if (parsedError === error) { // error is a primitive value const eventData = createLogEvent({ method: 'error', trace: [], args: [error], timestamp: Date.now(), }) fudgeLog.info('ConsoleEvent', eventData) const uid = nanoid() if (eventData) { await postEvent({ type: FudgeEventType.Console, data: eventData, timestamp: Date.now(), traceId, uid, }) } } else { // Error is an object let trace: StackFrame[] | undefined try { trace = ErrorStackParser.parse(error as any) } catch (e) { fudgeLog.info("Couldn't parse error") } const {message, code, name, stack, ...extraData} = parsedError const event: ErrorEvent = { type: FudgeEventType.Error, data: {trace, message: message || `Unknown error`, code, name, extraData}, timestamp: Date.now(), traceId, } fudgeLog.info('ErrorEvent', event) await postEvent(event) } await waitForPendingEvents() throw error } }) fudgeLog.info('ctx.resEndPromise here', resEndPromise.current != null) await resEndPromise.current fudgeLog.info('Handler is resolving now...') } }