Skip to content

Conversation

@TooTallNate
Copy link
Member

@TooTallNate TooTallNate commented Jan 14, 2026

Added support for "use step" directive in class instance methods, allowing instance methods to be used as workflow steps.

What changed?

  • Modified the SWC plugin to recognize and transform instance methods with the "use step" directive
  • Added registration logic for instance method steps using ClassName.prototype.methodName
  • Implemented proper serialization of class instances to preserve the this context across workflow/step boundaries
  • Added comprehensive end-to-end tests for instance method steps
  • Updated error handling to allow "use step" in instance methods while still preventing "use workflow" in instance methods

How to test?

The PR includes a new end-to-end test instanceMethodStepWorkflow that demonstrates the functionality:

  1. Run the e2e tests to verify the new instance method step functionality
  2. The test creates a Counter class with instance methods marked as steps
  3. It verifies that the instance methods can be called as steps with proper serialization of the this context
  4. It also verifies that multiple instances of the same class can be used independently

Why make this change?

This change enables a more natural object-oriented programming model when working with workflows. Previously, only static methods, standalone functions, and object methods could be marked as steps. Now, developers can create classes with instance methods that are steps, allowing for better encapsulation and more intuitive code organization. This is particularly useful for complex workflows that need to maintain state across multiple step invocations.

@changeset-bot
Copy link

changeset-bot bot commented Jan 14, 2026

🦋 Changeset detected

Latest commit: 16dd859

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
@workflow/swc-plugin Patch
@workflow/astro Patch
@workflow/builders Patch
@workflow/cli Patch
@workflow/nest Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
workflow Patch
@workflow/vite Patch
@workflow/world-testing Patch
@workflow/docs-typecheck Patch
@workflow/nuxt Patch
@workflow/core Patch
@workflow/web-shared Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Contributor

vercel bot commented Jan 14, 2026

@github-actions
Copy link
Contributor

github-actions bot commented Jan 14, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 479 0 38 517
✅ 💻 Local Development 438 0 32 470
✅ 📦 Local Production 438 0 32 470
✅ 🐘 Local Postgres 438 0 32 470
✅ 🪟 Windows 47 0 0 47
❌ 🌍 Community Worlds 31 169 0 200
✅ 📋 Other 129 0 12 141
Total 2000 169 146 2315

❌ Failed Tests

🌍 Community Worlds (169 failed)

mongodb (42 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • readableStreamWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • outputStreamWorkflow
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

redis (42 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • readableStreamWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • outputStreamWorkflow
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

starter (43 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • readableStreamWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • outputStreamWorkflow
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • health check (CLI) - workflow health command reports healthy endpoints
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

turso (42 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • readableStreamWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • outputStreamWorkflow
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 43 0 4
✅ example 43 0 4
✅ express 43 0 4
✅ fastify 43 0 4
✅ hono 43 0 4
✅ nextjs-turbopack 46 0 1
✅ nextjs-webpack 46 0 1
✅ nitro 43 0 4
✅ nuxt 43 0 4
✅ sveltekit 43 0 4
✅ vite 43 0 4
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 43 0 4
✅ express-stable 43 0 4
✅ fastify-stable 43 0 4
✅ hono-stable 43 0 4
✅ nextjs-turbopack-stable 47 0 0
✅ nextjs-webpack-stable 47 0 0
✅ nitro-stable 43 0 4
✅ nuxt-stable 43 0 4
✅ sveltekit-stable 43 0 4
✅ vite-stable 43 0 4
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 43 0 4
✅ express-stable 43 0 4
✅ fastify-stable 43 0 4
✅ hono-stable 43 0 4
✅ nextjs-turbopack-stable 47 0 0
✅ nextjs-webpack-stable 47 0 0
✅ nitro-stable 43 0 4
✅ nuxt-stable 43 0 4
✅ sveltekit-stable 43 0 4
✅ vite-stable 43 0 4
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 43 0 4
✅ express-stable 43 0 4
✅ fastify-stable 43 0 4
✅ hono-stable 43 0 4
✅ nextjs-turbopack-stable 47 0 0
✅ nextjs-webpack-stable 47 0 0
✅ nitro-stable 43 0 4
✅ nuxt-stable 43 0 4
✅ sveltekit-stable 43 0 4
✅ vite-stable 43 0 4
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 47 0 0
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 3 0 0
❌ mongodb 5 42 0
✅ redis-dev 3 0 0
❌ redis 5 42 0
✅ starter-dev 3 0 0
❌ starter 4 43 0
✅ turso-dev 3 0 0
❌ turso 5 42 0
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 43 0 4
✅ e2e-local-postgres-nest-stable 43 0 4
✅ e2e-local-prod-nest-stable 43 0 4

📋 View full workflow run

@TooTallNate TooTallNate merged commit c1d7c8d into main Feb 3, 2026
93 checks passed
@TooTallNate TooTallNate deleted the 01-13-add_support_for_use_step_functions_in_class_instance_methods branch February 3, 2026 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants