diff --git a/packages/runtime/src/components.ts b/packages/runtime/src/components.ts index 23fd4929a..f642b48f5 100644 --- a/packages/runtime/src/components.ts +++ b/packages/runtime/src/components.ts @@ -92,7 +92,11 @@ export function createComponent< */ action?: RuntimeCallback< [ComponentInstance, ComponentAction], - Promise<{ props?: Props; state?: State } | undefined>, + Promise< + | { type?: 'element'; props?: Props; state?: State } + | { type: 'complete'; returnValue?: PlainObject } + | undefined + >, Context >; @@ -129,29 +133,41 @@ export function createComponent< dynamicState: (key) => ({ $state: key }), }; + const respondWithOutput = (output: ContentKitRenderOutput) => { + return new Response(JSON.stringify(output), { + headers: { + 'Content-Type': 'application/json', + ...(cache + ? { + // @ts-ignore - I'm not sure how to fix this one with TS + 'Cache-Control': `max-age=${cache.maxAge}`, + } + : {}), + }, + }); + }; + if (action && component.action) { - instance = { ...instance, ...(await component.action(instance, action, context)) }; + const actionResult = await component.action(instance, action, context); + + // If the action is complete, return the result directly. No need to render the component. + if (actionResult?.type === 'complete') { + return respondWithOutput(actionResult); + } + + instance = { ...instance, ...actionResult }; } const element = await component.render(instance, context); const output: ContentKitRenderOutput = { + type: 'element', state: instance.state, props: instance.props, element, }; - return new Response(JSON.stringify(output), { - headers: { - 'Content-Type': 'application/json', - ...(cache - ? { - // @ts-ignore - I'm not sure how to fix this one with TS - 'Cache-Control': `max-age=${cache.maxAge}`, - } - : {}), - }, - }); + return respondWithOutput(output); }, }; -} \ No newline at end of file +}