### Clone Repository and Navigate Source: https://github.com/inngest/workflow-kit/blob/main/examples/nextjs-blog-cms/README.md Clone the repository and navigate into the example's directory to begin setup. ```bash git clone cd examples/nextjs-blog-cms ``` -------------------------------- ### Complete Editor Setup with Inngest Workflow Kit Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/ui-components.md This snippet demonstrates a full setup of the Inngest Workflow Kit's UI components, including the Provider, Editor, and Sidebar. It shows how to initialize the engine with custom actions and manage workflow state. Use this as a starting point for building your own workflow editor. ```typescript import React, { useState } from 'react'; import { Provider, Editor, Sidebar } from '@inngest/workflow-kit/ui'; import { Engine, type Workflow } from '@inngest/workflow-kit'; import '@inngest/workflow-kit/ui/ui.css'; const engine = new Engine({ actions: [ { kind: 'send-email', name: 'Send Email', description: 'Send an email message', handler: async ({ step }) => { return await step.run('send', async () => ({ messageId: 'msg-123', success: true })); }, inputs: { to: { type: Type.String({ title: 'To' }) }, subject: { type: Type.String({ title: 'Subject' }) } }, outputs: { messageId: { type: Type.String(), description: 'Message ID' }, success: { type: Type.Boolean(), description: 'Whether email sent' } } } ] }); export default function WorkflowEditor() { const [workflow, setWorkflow] = useState({ actions: [], edges: [] }); const publicActions = Object.values(engine.actions).map(a => ({ kind: a.kind, name: a.name, description: a.description, inputs: a.inputs, outputs: a.outputs, icon: a.icon, edges: a.edges })); const trigger = { name: 'user.signup', data: {} }; const handleSave = async () => { // Validate workflow try { engine.graph(workflow); console.log('Workflow valid'); // Save to database await fetch('/api/workflows', { method: 'POST', body: JSON.stringify(workflow) }); } catch (error) { console.error('Invalid workflow:', error); } }; return (
); } ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/inngest/workflow-kit/blob/main/examples/nextjs-blog-cms/README.md Install the necessary project dependencies using npm, yarn, or pnpm. ```bash npm i # or yarn # or pnpm --ignore-workspace i ``` -------------------------------- ### Start Next.js Development Server Source: https://github.com/inngest/workflow-kit/blob/main/examples/nextjs-blog-cms/README.md Start the Next.js application locally. Access the application at http://localhost:3000. ```bash npm run dev # or yarn dev # or pnpm dev # or bun dev ``` -------------------------------- ### Complete Database Query Action Example Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/action-creation.md An example of a complete database query action, including input/output schemas and a handler that executes a SQL query. ```typescript import { Type } from '@sinclair/typebox'; import { EngineAction } from '@inngest/workflow-kit'; export const queryDatabaseAction: EngineAction = { kind: 'query-database', name: 'Query Database', description: 'Execute a SQL query and return results', icon: '...', inputs: { query: { type: Type.String({ title: 'SQL Query', description: 'SQL query to execute', examples: ['SELECT * FROM users WHERE id = $1'] }), fieldType: 'textarea' }, timeout: { type: Type.Optional( Type.Number({ title: 'Timeout (seconds)', minimum: 1, default: 30 }) ) } }, outputs: { rows: { type: Type.Array(Type.Object({}, { additionalProperties: true })), description: 'Array of result rows' }, rowCount: { type: Type.Number(), description: 'Number of rows returned' }, error: { type: Type.Optional(Type.String()), description: 'Error message if query failed' } }, handler: async ({ workflowAction, step }) => { const { query, timeout = 30 } = workflowAction.inputs; return await step.run('query-database', async () => { try { const result = await executeQuery(query, { timeout }); return { rows: result.rows, rowCount: result.rowCount, error: null }; } catch (error) { return { rows: [], rowCount: 0, error: error.message }; } }); } }; ``` -------------------------------- ### Example Action Outputs Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/types.md This example demonstrates how to define multiple outputs for an action using the ActionOutput interface. It specifies the type and description for each output field. ```typescript const outputs = { messageId: { type: Type.String({ title: "Message ID" }), description: "The unique ID of the sent message" }, status: { type: Type.String({ enum: ['sent', 'failed'] }), description: "Whether the message was successfully sent" } }; ``` -------------------------------- ### Install Workflow Kit and Inngest Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/README.md Install the necessary packages for the Inngest Workflow Kit and Inngest. Requires Node.js 18+, React 18+ for UI, and TypeScript 5.0+ is recommended. ```bash npm install @inngest/workflow-kit inngest ``` -------------------------------- ### Simple Value Reference Example Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/interpolation.md Shows how to pass the output from a previous action directly as an input to a new action. ```typescript const inputs = { recipientId: "!ref($.fetch-user.userId)" }; const resolved = resolveInputs(inputs, { state: { 'fetch-user': { userId: 123 } }, event: { data: {} } }); // → { recipientId: 123 } ``` -------------------------------- ### Example ActionInput Configurations Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/types.md Demonstrates how to define input fields for actions, including a single-line text input for email and a textarea for content. ```typescript const emailInput: ActionInput = { type: Type.String({ title: "Email Address", description: "Recipient email address", format: "email" }), fieldType: "text" }; const contentInput: ActionInput = { type: Type.String({ title: "Content", description: "Email body content" }), fieldType: "textarea" }; ``` -------------------------------- ### Example Workflow Definition Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/types.md Illustrates how to define a simple workflow with a name, description, and a sequence of actions connected by edges. ```typescript const workflow: Workflow = { name: "Email Review Workflow", description: "Send email and wait for approval", actions: [ { id: "send-email", kind: "send-email", inputs: { to: "reviewer@example.com" } }, { id: "wait-approval", kind: "wait-for-event", inputs: { event: "approved" } } ], edges: [ { from: "$source", to: "send-email" }, { from: "send-email", to: "wait-approval" } ] }; ``` -------------------------------- ### Install Workflow Kit and Inngest SDK Source: https://github.com/inngest/workflow-kit/blob/main/README.md Install the Workflow Kit and the Inngest TypeScript SDK using npm. This is a required dependency for using the Workflow Kit. ```shell npm install @inngest/workflow-kit inngest ``` -------------------------------- ### Start Inngest Dev Server Source: https://github.com/inngest/workflow-kit/blob/main/examples/nextjs-blog-cms/README.md Start the Inngest Dev Server to manage and monitor workflows. Access the Inngest Dev Server at http://localhost:8288. ```bash npx inngest-cli@latest dev ``` -------------------------------- ### Create Workflow with Multiple Starting Actions Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/graph.md Shows a valid workflow configuration where multiple actions can be initiated directly from the source node. ```typescript const workflow = { actions: [ { id: 'email', kind: 'send-email' }, { id: 'sms', kind: 'send-sms' } ], edges: [ { from: '$source', to: 'email' }, { from: '$source', to: 'sms' } ] }; const dag = newDAG(workflow); // ✓ Both actions execute ``` -------------------------------- ### Sidebar Component Usage Example Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/ui-components.md Demonstrates how to use the Sidebar component within an application, alongside an Editor and Provider. ```typescript import { Sidebar } from '@inngest/workflow-kit/ui'; function App() { return (
); } ``` -------------------------------- ### Implement Workflow Loader Example Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/types.md An example implementation of the Loader function that fetches a workflow by its ID from a database. It throws an error if the workflow is not found, otherwise returns the workflow object. ```typescript const loader: Loader = async (event) => { const { workflowId } = event.data; const workflow = await database.workflows.findById(workflowId); if (!workflow) { throw new Error(`Workflow ${workflowId} not found`); } return workflow; }; ``` -------------------------------- ### Create Engine Instance with Custom Actions Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/engine.md Instantiate an Engine with a custom set of actions. This example demonstrates registering a 'send-email' action. ```typescript import { Engine } from '@inngest/workflow-kit'; const engine = new Engine({ actions: [ { kind: 'send-email', name: 'Send Email', handler: async ({ step, workflowAction, event }) => { return await step.run('send email', async () => { // Implementation return { success: true }; }); }, inputs: { to: { type: Type.String({ title: 'Email' }) } } } ] }); ``` -------------------------------- ### Example Workflow Structure with Source Node Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/graph.md Illustrates a basic workflow structure including edges originating from the SourceNodeID to the first action. ```typescript const workflow = { actions: [{ id: 'first', kind: 'action' }], edges: [ { from: SourceNodeID, to: 'first' } // Edge from trigger ] }; ``` -------------------------------- ### Source Action for Workflow Start Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/workflow-validation.md Ensures at least one action in the workflow is initiated by an edge originating from the '$source'. This guarantees the workflow has a defined starting point. ```typescript { actions: [ { id: 'email', kind: 'send-email' } ], edges: [ // ✗ No edge from $source ] } ``` ```typescript { actions: [ { id: 'email', kind: 'send-email' }, { id: 'archive', kind: 'archive' } ], edges: [ { from: 'email', to: 'archive' } // ✗ Doesn't start from $source ] } ``` ```typescript { actions: [ { id: 'email', kind: 'send-email' } ], edges: [ { from: '$source', to: 'email' } // ✓ Starts from source ] } ``` -------------------------------- ### Basic JSONPath References Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/interpolation.md Examples of accessing event data and previous action outputs using JSONPath expressions within the !ref syntax. ```javascript // Access event data !ref($.event.data.email) // → event.data.email !ref($.event.data.user.name) // → event.data.user.name !ref($.event.metadata.timestamp) // → event.metadata.timestamp // Access previous action output !ref($.previousAction) // → entire output !ref($.myAction.result) // → myAction.result !ref($.send-email.messageId) // → access action with hyphenated ID // Special path for immediate previous output in conditionals !ref($.output.result) // → output from previous action ``` -------------------------------- ### Event Data Reference Example Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/interpolation.md Illustrates using data from the triggering event, such as email and document names, within action inputs. ```typescript const inputs = { email: "!ref($.event.data.email)", subject: "Review required for: !ref($.event.data.documentName)" }; const resolved = resolveInputs(inputs, { state: {}, event: { data: { email: 'admin@example.com', documentName: 'Q4 Report' } } }); // → { // email: 'admin@example.com', // subject: 'Review required for: Q4 Report' // } ``` -------------------------------- ### Avoiding Cycles in Workflow Edges Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/workflow-validation.md Shows an example of a workflow edge configuration that creates a cycle and the recommended branching alternative. ```typescript // ✗ Wrong edges: [ { from: '$source', to: 'a' }, { from: 'a', to: 'b' }, { from: 'b', to: 'a' } // Cycle! ] // ✓ Correct (use branching instead) edges: [ { from: '$source', to: 'a' }, { from: 'a', to: 'b' }, { from: 'a', to: 'c' } ] ``` -------------------------------- ### Basic If/Else Workflow Example Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/builtin-actions.md Demonstrates a basic workflow using `builtin:if` to route based on an event status, sending different emails for 'approved' and other statuses. ```typescript const workflow = { actions: [ { id: 'check-status', kind: 'builtin:if', inputs: { condition: { "==": ["!ref($.event.data.status)", "approved"] } } }, { id: 'send-approval', kind: 'send-email', inputs: { to: 'admin@example.com', subject: 'Approved' } }, { id: 'send-rejection', kind: 'send-email', inputs: { to: 'user@example.com', subject: 'Rejected' } } ], edges: [ { from: '$source', to: 'check-status' }, { from: 'check-status', to: 'send-approval', name: 'True', conditional: { type: 'if', ref: '!ref($.output.result)' } }, { from: 'check-status', to: 'send-rejection', name: 'False', conditional: { type: 'else', ref: '!ref($.output.result)' } } ] }; ``` -------------------------------- ### Workflow Editor Example with Provider, Editor, and Sidebar Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/ui-components.md Demonstrates how to set up and use the Provider component to wrap the Editor and Sidebar for a functional workflow editor. Ensure all necessary imports are included. ```typescript import { Provider, Editor, Sidebar } from '@inngest/workflow-kit/ui'; import { Engine } from '@inngest/workflow-kit'; const engine = new Engine({ actions: [ // your actions ] }); function WorkflowEditor() { const [workflow, setWorkflow] = useState({ actions: [], edges: [] }); const trigger = { name: 'blog-post.created', data: {} }; return ( ({ kind: action.kind, name: action.name, description: action.description, inputs: action.inputs, outputs: action.outputs, icon: action.icon, edges: action.edges }))} onChange={setWorkflow} >
); } ``` -------------------------------- ### Populate Action Picker Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/ui-components.md Example demonstrating how to use `useAvailableActions` to populate a select dropdown with available workflow actions. Each action's kind is used as the key. ```typescript const ActionPicker = () => { const actions = useAvailableActions(); return ( ); }; ``` -------------------------------- ### Workflow Loader and Execution Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/inngest-integration.md Implement a workflow loader to dynamically fetch workflows from a database based on incoming events. This example shows how to initialize an Engine with a custom loader and execute a workflow, storing its final state. ```typescript const engine = new Engine({ actions: [/* actions */], loader: async (event) => { const { workflowId } = event.data; const workflow = await db.workflows.find(workflowId); if (!workflow) { throw new Error(`Workflow ${workflowId} not found`); } return workflow; } }); export const executeWorkflow = inngest.createFunction( { id: 'execute-workflow' }, { event: 'workflow.trigger' }, async ({ event, step }) => { // Workflow is automatically loaded from database const execution = await engine.run({ event, step }); // Store final state await db.executions.create({ workflowId: event.data.workflowId, state: Object.fromEntries(execution.state) }); } ); ``` -------------------------------- ### Create Engine with Custom Action Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/quick-start.md Define a custom action for the engine, specifying its inputs, outputs, and handler logic. This example defines a 'send-email' action. ```typescript import { Engine, EngineAction, type Workflow } from '@inngest/workflow-kit'; import { Type } from '@sinclair/typebox'; const sendEmailAction: EngineAction = { kind: 'send-email', name: 'Send Email', description: 'Send an email message', inputs: { to: { type: Type.String({ title: 'To', format: 'email' }) }, subject: { type: Type.String({ title: 'Subject' }) }, body: { type: Type.String({ title: 'Body' }) } }, outputs: { messageId: { type: Type.String(), description: 'Message ID' }, success: { type: Type.Boolean(), description: 'Success status' } }, handler: async ({ workflowAction, step }) => { const { to, subject, body } = workflowAction.inputs; return await step.run('send-email', async () => { // Your implementation here return { messageId: 'msg-123', success: true }; }); } }; const engine = new Engine({ actions: [sendEmailAction] }); ``` -------------------------------- ### Invalid Input Types for Workflow Actions Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/workflow-validation.md Illustrates type mismatches for inputs, showing examples that will fail validation. ```typescript // Type mismatch { id: 'a', kind: 'action', inputs: { count: 'not-a-number' } } // ✗ Expected number { id: 'a', kind: 'action', inputs: { name: 123 } } // ✗ Expected string { id: 'a', kind: 'action', inputs: { enabled: 1 } } // ✗ Expected boolean ``` -------------------------------- ### Complete Inngest Integration with Workflow Loader Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/inngest-integration.md A full Inngest integration example demonstrating action definition, engine creation with a custom loader, and an Inngest function for triggering and managing workflow executions. Includes error handling and state persistence. ```typescript import { Inngest } from 'inngest'; import { Engine, type Workflow } from '@inngest/workflow-kit'; import { Type } from '@sinclair/typebox'; const inngest = new Inngest({ id: 'my-app' }); // Define actions const sendEmailAction: EngineAction = { kind: 'send-email', name: 'Send Email', handler: async ({ step, workflowAction }) => { const { to, subject, body } = workflowAction.inputs; return await step.run('send-email', async () => { const result = await sendEmail({ to, subject, body }); return { messageId: result.id }; }); }, inputs: { to: { type: Type.String({ format: 'email' }) }, subject: { type: Type.String() }, body: { type: Type.String() } } }; // Create engine const engine = new Engine({ actions: [sendEmailAction], loader: async (event) => { const workflow = await db.workflows.find(event.data.workflowId); if (!workflow) throw new Error('Workflow not found'); return workflow; } }); // Create Inngest function export const executeWorkflow = inngest.createFunction( { id: 'execute-workflow', retries: 3, concurrency: { limit: 20, key: 'event.data.userId' } }, { event: 'workflow.trigger' }, async ({ event, step }) => { try { const execution = await engine.run({ event, step }); // Store execution result await db.executions.create({ workflowId: event.data.workflowId, state: Object.fromEntries(execution.state), success: true }); return { success: true }; } catch (error) { await db.executions.create({ workflowId: event.data.workflowId, error: error.message, success: false }); throw error; // Let Inngest handle retries } } ); // Trigger execution export async function triggerWorkflow(workflowId: number, userId: string) { await inngest.send({ name: 'workflow.trigger', data: { workflowId, userId } }); } ``` -------------------------------- ### Conditional Routing in Workflow Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/README.md Illustrates how to implement conditional routing within a workflow. This example routes to 'action-a' if the 'approved' condition is true. ```typescript { from: 'check', to: 'action-a', name: 'True', conditional: { type: 'if', ref: '!ref($.output.approved)' } } ``` -------------------------------- ### Display Workflow Action Count Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/ui-components.md Example of using `useWorkflow` to display the number of actions in the current workflow. Ensure the workflow object is available before accessing its properties. ```typescript const MyComponent = () => { const workflow = useWorkflow(); return
Actions: {workflow?.actions.length}
; }; ``` -------------------------------- ### Define Action Inputs with TypeBox Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/action-creation.md Example of defining inputs for a 'send-email' action, including required and optional fields with TypeBox schemas and UI field types. ```typescript import { Type } from '@sinclair/typebox'; const sendEmailAction: EngineAction = { kind: 'send-email', handler: async ({ workflowAction }) => { const { to, subject } = workflowAction.inputs; // ... }, inputs: { to: { type: Type.String({ title: 'To', description: 'Email address', format: 'email' }), fieldType: 'text' }, subject: { type: Type.String({ title: 'Subject', description: 'Email subject line' }), fieldType: 'text' }, body: { type: Type.String({ title: 'Body', description: 'Email message' }), fieldType: 'textarea' }, cc: { type: Type.Optional( Type.String({ title: 'CC', description: 'Carbon copy address' }) ), fieldType: 'text' } } }; ``` -------------------------------- ### Catch Workflow Execution Errors Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/inngest-integration.md This example demonstrates how to catch errors during the execution of an entire Inngest workflow. It logs the error and returns a failure status. ```typescript export const executeWorkflow = inngest.createFunction( { id: 'execute-workflow' }, { event: 'workflow.execute' }, async ({ event, step }) => { try { const execution = await engine.run({ event, step, workflow: getUserWorkflow(event.data.userId) }); return { success: true, state: execution.state }; } catch (error) { // Log error console.error('Workflow failed:', error); // Could retry, send alert, etc. return { success: false, error: error.message }; } } ); ``` -------------------------------- ### Accessing Action Output from Execution State Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/engine.md This example demonstrates how to run a workflow and then access the output of a specific action, 'email-send-action', from the resulting execution state. It checks the success property of the retrieved output. ```typescript const execution = await engine.run({ event, step, workflow }); const emailOutput = execution.state.get('email-send-action'); console.log('Email sent successfully:', emailOutput.success); ``` -------------------------------- ### bfs() Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/graph.md Traverses the graph in breadth-first order, executing a callback for each action node. The traversal starts from the source node and processes actions level-by-level, respecting edge ordering and executing callbacks sequentially. ```APIDOC ## bfs() ### Description Traverses the graph in breadth-first order, executing a callback for each action node. ### Method Signature ```typescript async function bfs( graph: DAG, cb: (node: WorkflowAction, edge: WorkflowEdge) => Promise ): Promise ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters Table | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | graph | `DAG` | Yes | The workflow DAG | | cb | `(WorkflowAction, WorkflowEdge) => Promise` | Yes | Async callback executed for each action | ### Returns `Promise` - Resolves when entire graph is traversed ### Callback Parameters **`node: WorkflowAction`** - The action being executed - Contains: `id`, `kind`, `name`, `inputs` **`edge: WorkflowEdge`** - The edge leading to this action - Contains: `from`, `to`, `name`, `conditional` ### Example Usage ```typescript import { bfs, newDAG } from '@inngest/workflow-kit'; const dag = newDAG(workflow); await bfs(dag, async (action, edge) => { console.log(`Executing: ${action.name}`); if (edge.conditional) { console.log(` via edge: ${edge.name}`); } // Perform action execution here const result = await executeAction(action); return result; }); console.log('Workflow complete'); ``` ``` -------------------------------- ### Define Workflow Structure Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/quick-start.md Define the workflow's structure, including its name, actions, and the order of execution using edges. This example defines a 'Welcome Email' workflow. ```typescript const workflow: Workflow = { name: 'Welcome Email', actions: [ { id: 'send-welcome', kind: 'send-email', inputs: { to: '!ref($.event.data.email)', subject: 'Welcome to our service', body: 'Hello and welcome!' } } ], edges: [ { from: '$source', to: 'send-welcome' } ] }; ``` -------------------------------- ### Configure Step-Level Retries Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/inngest-integration.md Configure retry behavior for individual steps within an Inngest action handler. This example sets retries to 5 for a specific API call step. ```typescript const actionWithRetry: EngineAction = { kind: 'unreliable-api', handler: async ({ step }) => { return await step.run( 'api-call', async () => { return await callUnreliableApi(); }, { retries: 5 } ); } }; ``` -------------------------------- ### Initialize Engine Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/quick-start.md Instantiate the `Engine` with options, including a list of all action kinds to be registered. ```typescript const engine = new Engine({ actions: [sendEmailAction] // Must include all action kinds }); ``` -------------------------------- ### Test Functions Locally with Express Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/inngest-integration.md Set up a local Inngest environment using Express to test your functions. This snippet shows how to import `createClient` and use the `serve` utility to mount your Inngest functions. ```typescript import { createClient } from 'inngest'; import { serve } from 'inngest/express'; // In your API route export default serve({ client: inngest, functions: [executeWorkflow] }); ``` -------------------------------- ### Get Loader Function Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/engine.md Retrieve the currently configured loader function, which is used for dynamically loading workflows from events. ```typescript get loader(): Loader | undefined ``` -------------------------------- ### Get Registered Actions Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/engine.md Retrieve all registered actions as a record keyed by their kind. Useful for inspecting available actions. ```typescript get actions(): Record ``` ```typescript const actionMap = engine.actions; const sendEmailAction = actionMap['send-email']; ``` -------------------------------- ### Get Trigger Definition Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/ui-components.md The `useTrigger` hook retrieves the definition of the trigger or event for the current workflow. The return type is 'any'. ```typescript const useTrigger = (): any ``` -------------------------------- ### Deploy to Vercel Source: https://github.com/inngest/workflow-kit/blob/main/examples/nextjs-blog-cms/README.md Deploy the Next.js blog CMS template to Vercel using the provided button. Ensure the OPENAI_API_KEY environment variable is configured after deployment. ```bash pnpm --ignore-workspace i ``` -------------------------------- ### Import UI Components - With Styles Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/api-index.md Import the UI components along with their associated CSS styles. ```typescript import '@inngest/workflow-kit/ui/ui.css'; ``` -------------------------------- ### Get Available Actions Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/ui-components.md Use `useAvailableActions` to fetch a list of all actions that can be used within the workflow. This is useful for populating selection components. ```typescript const useAvailableActions = (): PublicEngineAction[] ``` -------------------------------- ### Get Current Workflow Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/ui-components.md Use the `useWorkflow` hook to access the workflow currently being edited. Returns the workflow object or undefined if not available. ```typescript const useWorkflow = (): Workflow | undefined ``` -------------------------------- ### Engine.run() Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/engine.md Executes a workflow durably using Inngest's step functionality. The workflow can be provided directly or loaded via a configured loader. ```APIDOC ## Engine.run() ### Description Executes a workflow durably using Inngest's step functionality. The workflow can be provided directly or loaded via the configured loader. ### Method Not applicable (SDK method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body * **args.event** (`any`) - Yes - The event that triggered the workflow * **args.step** (`any`) - Yes - Inngest step tools for durable execution * **args.workflow** (`Workflow`) - No - The workflow to execute (required if no loader configured) ### Response #### Success Response * **Promise** - The execution state containing accumulated action outputs #### Response Example ```typescript // Example of an ExecutionState object (structure depends on ExecutionState implementation) { // ... ExecutionState structure ... } ``` ERROR HANDLING: - `Error` - "Cannot run workflows without a workflow instance specified." if neither workflow nor loader provided - `Error` - "No workflow instance specified." if loader returns null/undefined ### Example ```typescript const inngest = new Inngest({ id: 'app' }); export const myWorkflow = inngest.createFunction( { id: 'execute-workflow' }, { event: 'workflow.execute' }, async ({ event, step }) => { const execution = await engine.run({ event, step, workflow: myWorkflow }); console.log('Workflow outputs:', execution.state); } ); ``` ``` -------------------------------- ### Create Inngest Client Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/inngest-integration.md Initialize the Inngest client with a unique application ID. Optional configuration for the Inngest API key is available. ```typescript import { Inngest } from 'inngest'; export const inngest = new Inngest({ id: 'my-app', // Optional: Configure with your Inngest API key }); ``` -------------------------------- ### Configure Function-Level Retries Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/inngest-integration.md Configure the number of times an Inngest function should automatically retry upon failure. This example sets retries to 3. ```typescript export const executeWorkflow = inngest.createFunction( { id: 'execute-workflow', retries: 3 // Retry up to 3 times }, { event: 'workflow.execute' }, async ({ event, step }) => { return await engine.run({ event, step, workflow }); } ); ``` -------------------------------- ### Conditional Edge Reference Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/interpolation.md Example of using a reference in a conditional edge evaluation for routing logic based on the success status of a previous action. ```typescript const edge = { conditional: { type: "if", ref: "!ref($.send-email.success)" } }; const vars = { state: { 'send-email': { success: true } }, event: { data: {} } }; // Evaluated as truthy/falsy for conditional routing ``` -------------------------------- ### Chaining Actions in Workflow Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/README.md Demonstrates how to chain multiple actions together in a workflow. The output of one action ('fetch-user') is used as input for the next ('send-email'). ```typescript { from: '$source', to: 'fetch-user' }, { from: 'fetch-user', to: 'send-email', inputs: { to: '!ref($.fetch-user.email)' } } ``` -------------------------------- ### Execute Workflow with Engine.run() Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/engine.md Executes a workflow durably using Inngest's step functionality. Requires an event, step tools, and optionally the workflow definition itself. Use this within an Inngest function to run your defined workflows. ```typescript const inngest = new Inngest({ id: 'app' }); export const myWorkflow = inngest.createFunction( { id: 'execute-workflow' }, { event: 'workflow.execute' }, async ({ event, step }) => { const execution = await engine.run({ event, step, workflow: myWorkflow }); console.log('Workflow outputs:', execution.state); } ); ``` -------------------------------- ### Get Workflow OnChange Handler Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/ui-components.md The `useOnChange` hook provides a callback function to modify the workflow. This function accepts an updated workflow object. ```typescript const useOnChange = (): (w: Workflow) => void ``` -------------------------------- ### Action Handler Using Inngest Step Tools Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/action-creation.md Illustrates the use of Inngest's durable `step` tools within an action handler, including `step.run` for durable execution, `step.sleep` for delays, and `step.waitForEvent` for event-driven waits. ```typescript const myAction: EngineAction = { kind: 'multi-step-action', handler: async ({ step, event }) => { // Run a durable step const result1 = await step.run('step-1', async () => { return await callApi(); }); // Sleep/wait await step.sleep('wait', '1 hour'); // Wait for an event const approval = await step.waitForEvent( 'wait-approval', 'approval.submitted', { timeout: '24 hours' } ); // Run another step const result2 = await step.run('step-2', async () => { return await processApproval(approval); }); return { result1, result2 }; } }; ``` -------------------------------- ### Import Core API - Individual Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/api-index.md Import individual core API elements like Engine, Workflow, and EngineAction from the workflow kit. ```typescript import { Engine } from '@inngest/workflow-kit'; import type { Workflow, EngineAction } from '@inngest/workflow-kit'; ``` -------------------------------- ### Editor Component Usage Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/ui-components.md Example of how to use the `Editor` component within a React application. It requires a `Provider` component to supply workflow data and callbacks. ```typescript import { Editor } from '@inngest/workflow-kit/ui'; function App() { return ( ); } ``` -------------------------------- ### Update Workflow Name Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/ui-components.md Example of using `useOnChange` and `useWorkflow` to update the name of the workflow when a button is clicked. A new workflow object is created with the updated name. ```typescript const SaveButton = () => { const onChange = useOnChange(); const workflow = useWorkflow(); return ( ); }; ``` -------------------------------- ### Basic Action Structure with Engine Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/action-creation.md Defines a custom action with its kind, name, description, handler, inputs, and outputs. It's then added to an Inngest Engine. ```typescript import { Type } from '@sinclair/typebox'; import { Engine, EngineAction } from '@inngest/workflow-kit'; const myAction: EngineAction = { kind: 'unique-action-id', name: 'Action Display Name', description: 'What this action does', handler: async ({ event, step, workflow, workflowAction, state }) => { // Execution logic here return { result: 'output' }; }, inputs: { // Define input fields }, outputs: { // Define output structure } }; const engine = new Engine({ actions: [myAction] }); ``` -------------------------------- ### Import Core API - Namespace Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/api-index.md Import the entire workflow kit as a namespace for accessing its core API elements. ```typescript import * as WfKit from '@inngest/workflow-kit'; const engine = new WfKit.Engine({...}); ``` -------------------------------- ### Create Inngest Function to Execute Workflow Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/quick-start.md Create an Inngest function that listens for a specific event ('user.signed-up') and runs the defined workflow using the engine. ```typescript import { Inngest } from 'inngest'; const inngest = new Inngest({ id: 'my-app' }); export const executeWorkflow = inngest.createFunction( { id: 'execute-workflow' }, { event: 'user.signed-up' }, async ({ event, step }) => { const execution = await engine.run({ event, step, workflow }); console.log('Workflow completed, final state:', execution.state); } ); ``` -------------------------------- ### Engine Constructor Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/engine.md Creates a new Engine instance for managing workflows and their actions. It takes an EngineOptions object for configuration. ```APIDOC ## Engine Constructor ### Description Creates a new Engine instance for managing workflows and their actions. ### Signature ```typescript constructor(options: EngineOptions) ``` ### Parameters #### options (`EngineOptions`) - **Type**: `EngineOptions` - **Required**: Yes - **Description**: Configuration object containing actions and optional loader. ##### EngineOptions - **actions** (`EngineAction[]`): Optional - Array of workflow actions available in this engine. - **disableBuiltinActions** (`boolean`): Optional - Set to true to disable the built-in If/Else action. Defaults to `false`. - **loader** (`Loader`): Optional - Function to load workflow definitions from events. ### Example ```typescript import { Engine } from '@inngest/workflow-kit'; const engine = new Engine({ actions: [ { kind: 'send-email', name: 'Send Email', handler: async ({ step, workflowAction, event }) => { return await step.run('send email', async () => { // Implementation return { success: true }; }); }, inputs: { to: { type: Type.String({ title: 'Email' }) } } } ] }); ``` ``` -------------------------------- ### Conditional References Validation Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/workflow-validation.md This example shows a workflow with a conditional edge. While `engine.graph()` passes static validation, the invalid reference `$.nonexistent` will cause a runtime error. ```typescript const workflow = { actions: [ { id: 'check', kind: 'builtin:if' }, { id: 'email', kind: 'send-email' } ], edges: [ { from: '$source', to: 'check' }, { from: 'check', to: 'email', conditional: { type: 'if', ref: '!ref($.nonexistent)' // ✗ Not validated } } ] }; engine.graph(workflow); // ✓ Validation passes // But at runtime, ref evaluates to undefined ``` -------------------------------- ### Import UI Components - Individual Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/api-index.md Import individual UI components such as Editor, Sidebar, Provider, and the useWorkflow hook. ```typescript import { Editor, Sidebar, Provider } from '@inngest/workflow-kit/ui'; import { useWorkflow } from '@inngest/workflow-kit/ui'; ``` -------------------------------- ### Ensure All Actions Are Connected in Workflow Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/workflow-validation.md This example shows an invalid workflow where the 'archive' action is disconnected. Ensure all actions are reachable from the source node or a preceding action. ```typescript { actions: [ { id: 'email', kind: 'send-email' }, { id: 'archive', kind: 'archive' } ], edges: [ { from: '$source', to: 'email' } // ✗ No path to 'archive' ] } ``` ```typescript { actions: [ { id: 'check', kind: 'builtin:if' }, { id: 'email-true', kind: 'send-email' }, { id: 'email-false', kind: 'send-email' }, { id: 'orphan', kind: 'archive' } ], edges: [ { from: '$source', to: 'check' }, { from: 'check', to: 'email-true', conditional: { type: 'if', ref: '!ref($.output.result)' } }, { from: 'check', to: 'email-false', conditional: { type: 'else', ref: '!ref($.output.result)' } } // ✗ No path to 'orphan' ] } ``` ```typescript { actions: [ { id: 'email', kind: 'send-email' }, { id: 'archive', kind: 'archive' } ], edges: [ { from: '$source', to: 'email' }, { from: 'email', to: 'archive' } // ✓ All connected ] } ``` -------------------------------- ### Get Execution State Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/engine.md Retrieves the accumulated outputs from executed actions, keyed by action ID. Use this to access the results of previously completed actions in the workflow. ```typescript get state(): Map ``` -------------------------------- ### Integrate Workflow Graph with Engine Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/graph.md Shows how the Engine uses `newDAG` and `bfs` internally for graph creation and execution. ```typescript // Engine.graph() wraps newDAG() const dag = engine.graph(workflow); // Engine.run() uses bfs() for execution await bfs(dag, async (action, edge) => { const result = await executeAction(action); executionState.state.set(action.id, result); }); ``` -------------------------------- ### Define Custom Edges for Actions Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/action-creation.md Configure predefined edges for your action to guide workflow logic. 'allowAdd: false' prevents users from adding custom edges. ```typescript const conditionalAction: EngineAction = { kind: 'check-status', handler: async ({ workflowAction }) => { const approved = checkApprovalStatus(); return { approved }; }, inputs: { status: { type: Type.String() } }, outputs: { approved: { type: Type.Boolean() } }, edges: { allowAdd: false, // Users can't add custom edges edges: [ { name: 'Approved', conditional: { type: 'if', ref: '!ref($.output.approved)' } }, { name: 'Rejected', conditional: { type: 'else', ref: '!ref($.output.approved)' } } ] } }; ``` -------------------------------- ### Test Inngest Workflow Function Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/inngest-integration.md Use `testClient` to create a test client for your Inngest functions. This allows you to simulate sending events and assert on the results. ```typescript import { testClient } from 'inngest/test'; const client = testClient({ client: inngest, functions: [executeWorkflow] }); test('executes workflow', async () => { const result = await client.send({ name: 'workflow.trigger', data: { workflowId: 1, userId: 'user-1' } }); expect(result.runs).toHaveLength(1); }); ``` -------------------------------- ### Custom Inngest Editor Layout Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/quick-start.md Customize the layout of the Inngest Editor by providing custom styles or wrapping components. This example sets a two-column layout for the editor and sidebar. ```typescript
``` -------------------------------- ### React Components Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/DELIVERABLES.md The Workflow Kit provides React components for building and visualizing workflows. ```APIDOC ## React Components ### Provider Description: Provides the workflow context to child components. ### Editor Description: A component for editing workflow definitions. ### Sidebar Description: A sidebar component for workflow-related information or actions. ### Node Components Description: Reusable components for rendering different types of nodes in the workflow. ``` -------------------------------- ### If Action Condition Examples Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/builtin-actions.md The condition input for the 'If' action is a generic Object, accommodating various JSON Logic structures. Validation of the JSON Logic occurs at runtime. ```typescript { title: "Condition", description: "Condition to evaluate", examples: [ { "==": ["!ref($.event.data.likes)", "a"] }, { "and": [ { "==": ["!ref($.event.data.likes)", 1.123] }, { "==": ["!ref($.event.data.likes)", "b"] }, ] }, ] } ``` -------------------------------- ### Define Engine Options Source: https://github.com/inngest/workflow-kit/blob/main/_autodocs/types.md Configuration object passed to the Engine constructor. Use this to customize actions, disable built-in features, or provide a custom loader. ```typescript interface EngineOptions { actions?: Array; disableBuiltinActions?: boolean; loader?: Loader; } ```