feat(workflow-core): add createWorkflowFactory#8
Conversation
…+ defaults Pin shared middleware and step-retry defaults across a family of workflows. Factory middleware runs before per-workflow middleware; ctx extensions accumulate across both layers. Per-workflow config wins over factory defaults. `.extend(overrides?)` forks a child factory without mutating the parent.
📝 WalkthroughWalkthroughThis PR introduces ChangesWorkflow Factory Implementation
Sequence DiagramsequenceDiagram
participant Factory as createWorkflowFactory
participant Builder as WorkflowBuilder
participant Workflow as Produced Workflow
Factory->>Factory: buildFactory(middlewares, defaults)
Factory->>Builder: .middleware([...])
Builder->>Builder: accumulate middlewares
Builder->>Builder: return new builder instance
Factory->>Builder: .extend(overrides)
Builder->>Builder: shallow merge defaults
Builder->>Builder: copy middlewares
Builder->>Builder: return child factory
Factory->>Workflow: call factory with config
Workflow->>Workflow: merge defaultStepRetry
Workflow->>Workflow: apply factory middleware first
Workflow->>Workflow: apply per-workflow middleware
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/workflow-core/src/define/create-workflow-factory.ts`:
- Around line 127-130: createWorkflowFactory currently passes the caller's
config object by reference to buildFactory (defaults: config), risking mutation
leaks; fix this by defensively copying the config before passing it (e.g.,
create a shallow copy of CreateWorkflowFactoryConfig and pass that to
buildFactory) so createWorkflowFactory and buildFactory use an independent
defaults object and external mutations won't affect existing factories.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 19dc9e00-5de0-4c68-8f88-69e0e96f3af1
📒 Files selected for processing (7)
.changeset/workflow-factory.mddocs/concepts/middleware.mddocs/quick-start.mdpackages/workflow-core/README.mdpackages/workflow-core/src/define/create-workflow-factory.tspackages/workflow-core/src/index.tspackages/workflow-core/tests/workflow-factory.test.ts
| export function createWorkflowFactory( | ||
| config: CreateWorkflowFactoryConfig = {}, | ||
| ): WorkflowFactoryBuilder<unknown> { | ||
| return buildFactory({ middlewares: [], defaults: config }) |
There was a problem hiding this comment.
Defensively copy initial config to avoid mutation leaks.
Line 130 stores the caller’s config object by reference. If that object is mutated later, existing factories can change behavior unexpectedly.
Suggested fix
export function createWorkflowFactory(
config: CreateWorkflowFactoryConfig = {},
): WorkflowFactoryBuilder<unknown> {
- return buildFactory({ middlewares: [], defaults: config })
+ return buildFactory({ middlewares: [], defaults: { ...config } })
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function createWorkflowFactory( | |
| config: CreateWorkflowFactoryConfig = {}, | |
| ): WorkflowFactoryBuilder<unknown> { | |
| return buildFactory({ middlewares: [], defaults: config }) | |
| export function createWorkflowFactory( | |
| config: CreateWorkflowFactoryConfig = {}, | |
| ): WorkflowFactoryBuilder<unknown> { | |
| return buildFactory({ middlewares: [], defaults: { ...config } }) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/workflow-core/src/define/create-workflow-factory.ts` around lines
127 - 130, createWorkflowFactory currently passes the caller's config object by
reference to buildFactory (defaults: config), risking mutation leaks; fix this
by defensively copying the config before passing it (e.g., create a shallow copy
of CreateWorkflowFactoryConfig and pass that to buildFactory) so
createWorkflowFactory and buildFactory use an independent defaults object and
external mutations won't affect existing factories.
Summary
createWorkflowFactory(config?)lets a family of workflows share middleware and step-retry defaults without repeating.middleware([...])per workflow.appWorkflow.extend({ ... })forks a child factory with override defaults without mutating the parent.Implementation wraps
createWorkflowrather than reaching into builder internals, so the existing builder stays the single source of truth for ctx accumulation. The factory itself is a callable hybrid (function +.middleware()/.extend()methods) — drop-in shape forcreateWorkflow({ id }).Test plan
npx vitest run tests/workflow-factory.test.ts— 9 new tests pass (ctx extension, execution order, ctx accumulation across both layers, defaults merge with per-workflow winning,.extend()fork + overrides, factory.middleware()chaining, no-extra-mw case, empty-factory equivalence)npx vitest run— full 114-test suite passes (no regressions)npx tsc --noEmit— cleannpx nx run @tanstack/workflow-core:test:eslint— cleanSummary by CodeRabbit
New Features
createWorkflowFactoryto define reusable workflow configurations with shared middleware and default step-retry settings..extend()without mutating parent configuration.Documentation