@@ -361,25 +361,30 @@ export async function testMyIntegration(credentials: Record<string, string>) {
361361
362362** File:** ` plugins/my-integration/steps/send-message/step.ts `
363363
364- This runs on the server during workflow execution:
364+ This runs on the server during workflow execution. Steps use the ` withStepLogging ` wrapper to automatically log execution for the workflow builder UI :
365365
366366``` typescript
367367import " server-only" ;
368368
369369import { fetchCredentials } from " @/lib/credential-fetcher" ;
370+ import { type StepInput , withStepLogging } from " @/lib/steps/step-handler" ;
370371import { getErrorMessage } from " @/lib/utils" ;
371372
372- /**
373- * Send Message Step
374- * Sends a message using My Integration API
375- */
376- export async function sendMessageStep(input : {
373+ type SendMessageResult =
374+ | { success: true ; id: string ; url: string }
375+ | { success: false ; error: string };
376+
377+ // Extend StepInput to get automatic logging context
378+ export type SendMessageInput = StepInput & {
377379 integrationId? : string ;
378380 message: string ;
379381 channel: string ;
380- }) {
381- " use step" ;
382+ };
382383
384+ /**
385+ * Send message logic - separated for clarity and testability
386+ */
387+ async function sendMessage(input : SendMessageInput ): Promise <SendMessageResult > {
383388 const credentials = input .integrationId
384389 ? await fetchCredentials (input .integrationId )
385390 : {};
@@ -414,9 +419,9 @@ export async function sendMessageStep(input: {
414419 const result = await response .json ();
415420
416421 return {
422+ success: true ,
417423 id: result .id ,
418424 url: result .url ,
419- success: true ,
420425 };
421426 } catch (error ) {
422427 return {
@@ -425,8 +430,26 @@ export async function sendMessageStep(input: {
425430 };
426431 }
427432}
433+
434+ /**
435+ * Send Message Step
436+ * Sends a message using My Integration API
437+ */
438+ export async function sendMessageStep(
439+ input : SendMessageInput
440+ ): Promise <SendMessageResult > {
441+ " use step" ;
442+ return withStepLogging (input , () => sendMessage (input ));
443+ }
428444```
429445
446+ ** Key Points:**
447+
448+ 1 . ** Extend ` StepInput ` ** : Your input type should extend ` StepInput ` to include the optional ` _context ` for logging
449+ 2 . ** Separate logic function** : Keep the actual logic in a separate function for clarity and testability
450+ 3 . ** Wrap with ` withStepLogging ` ** : The step function just wraps the logic with ` withStepLogging(input, () => logic(input)) `
451+ 4 . ** Return success/error objects** : Steps should return ` { success: true, ... } ` or ` { success: false, error: "..." } `
452+
430453#### Step 6: Create Config UI Component
431454
432455** File:** ` plugins/my-integration/steps/send-message/config.tsx `
@@ -756,21 +779,42 @@ Use `TemplateBadgeInput` to allow users to reference outputs from other workflow
756779/>
757780```
758781
759- ### Pattern 2: Step Function Error Handling
782+ ### Pattern 2: Step Function Structure
783+
784+ Steps follow a consistent structure with logging:
760785
761786``` typescript
762- try {
763- const response = await fetch (/* ... */ );
764- if (! response .ok ) {
765- throw new Error (` API error: ${response .statusText } ` );
787+ import " server-only" ;
788+
789+ import { type StepInput , withStepLogging } from " @/lib/steps/step-handler" ;
790+
791+ type MyResult = { success: true ; data: string } | { success: false ; error: string };
792+
793+ export type MyInput = StepInput & {
794+ field1: string ;
795+ };
796+
797+ // 1. Logic function (no "use step" needed)
798+ async function myLogic(input : MyInput ): Promise <MyResult > {
799+ try {
800+ const response = await fetch (/* ... */ );
801+ if (! response .ok ) {
802+ throw new Error (` API error: ${response .statusText } ` );
803+ }
804+ const result = await response .json ();
805+ return { success: true , data: result };
806+ } catch (error ) {
807+ return {
808+ success: false ,
809+ error: ` Failed to execute: ${getErrorMessage (error )} ` ,
810+ };
766811 }
767- const result = await response .json ();
768- return { success: true , ... result };
769- } catch (error ) {
770- return {
771- success: false ,
772- error: ` Failed to execute: ${getErrorMessage (error )} ` ,
773- };
812+ }
813+
814+ // 2. Step wrapper (has "use step", wraps with logging)
815+ export async function myStep(input : MyInput ): Promise <MyResult > {
816+ " use step" ;
817+ return withStepLogging (input , () => myLogic (input ));
774818}
775819```
776820
0 commit comments