diff --git a/package.json b/package.json index ad0564b..9dc4479 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,8 @@ "format:check": "prettier \"src/**/*.ts\" --check", "lint": "eslint src --ext .ts --fix", "lint:check": "eslint src --ext .ts", - "test": "vitest run", - "test:watch": "vitest watch", + "test": "vitest run --typecheck", + "test:watch": "vitest watch --typecheck", "test:coverage": "vitest run --coverage", "test:setup": "tsx ./scripts/test-setup.ts", "spell:check": "cspell \"{README.md,CODE_OF_CONDUCT.md,CONTRIBUTING.md,.github/*.md,src/**/*.ts}\"", diff --git a/src/__tests__/types.test-d.ts b/src/__tests__/types.test-d.ts new file mode 100644 index 0000000..fd547d5 --- /dev/null +++ b/src/__tests__/types.test-d.ts @@ -0,0 +1,893 @@ +import * as E from '../errors.js'; +import * as T from '../types.js'; + +import { describe, expectTypeOf } from 'vitest'; + +import { Effect } from 'effect'; + +type Context = { context: boolean }; + +describe('types', () => { + describe('UpdateWorkflowContext', () => { + expectTypeOf>().toEqualTypeOf< + ( + contextOrUpdater: Context | ((context: Context) => Context) + ) => Effect.Effect + >(); + }); + + describe('DefaultTaskOrWorkItemActivityPayload', () => { + expectTypeOf< + T.DefaultTaskOrWorkItemActivityPayload + >().toEqualTypeOf<{ + getWorkflowContext: () => Effect.Effect; + updateWorkflowContext: T.UpdateWorkflowContext; + }>(); + }); + + describe('TaskOnStartPayload', () => { + expectTypeOf>().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + disableTask: () => Effect.Effect< + void, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.InvalidTaskStateTransition + >; + } + >(); + }); + + describe('TaskOnEnablePayload', () => { + expectTypeOf>().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + enableTask: () => Effect.Effect< + { + enqueueStartTask: (input?: unknown) => Effect.Effect; + }, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskStateTransition + >; + } + >(); + }); + + describe('TaskOnStartPayload', () => { + describe('TPayload !== undefined, TStartWorkItemInput !== undefined', () => { + expectTypeOf< + T.TaskOnStartPayload< + Context, + { payload: true }, + { startWorkItemInput: true } + > + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + startTask: () => Effect.Effect< + { + enqueueStartWorkItem( + id: T.WorkItemId, + input: { startWorkItemInput: true } + ): Effect.Effect; + initializeWorkItem: (payload: { + payload: true; + }) => Effect.Effect< + T.WorkItemInstance<{ payload: true }>, + E.TaskDoesNotExistInStore | E.InvalidTaskState + >; + }, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskStateTransition + >; + } + >(); + }); + + describe('TPayload === undefined, TStartWorkItemInput !== undefined', () => { + expectTypeOf< + T.TaskOnStartPayload + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + startTask: () => Effect.Effect< + { + enqueueStartWorkItem( + id: T.WorkItemId, + input: { startWorkItemInput: true } + ): Effect.Effect; + initializeWorkItem: ( + payload?: undefined + ) => Effect.Effect< + T.WorkItemInstance, + E.TaskDoesNotExistInStore | E.InvalidTaskState + >; + }, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskStateTransition + >; + } + >(); + }); + + describe('TPayload !== undefined, TStartWorkItemInput === undefined', () => { + expectTypeOf< + T.TaskOnStartPayload + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + startTask: () => Effect.Effect< + { + enqueueStartWorkItem( + id: T.WorkItemId, + input?: undefined + ): Effect.Effect; + initializeWorkItem: (payload: { + payload: true; + }) => Effect.Effect< + T.WorkItemInstance<{ payload: true }>, + E.TaskDoesNotExistInStore | E.InvalidTaskState + >; + }, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskStateTransition + >; + } + >(); + }); + + describe('TPayload === undefined, TStartWorkItemInput === undefined', () => { + expectTypeOf< + T.TaskOnStartPayload + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + startTask: () => Effect.Effect< + { + enqueueStartWorkItem( + id: T.WorkItemId, + input?: undefined + ): Effect.Effect; + initializeWorkItem: ( + payload?: undefined + ) => Effect.Effect< + T.WorkItemInstance, + E.TaskDoesNotExistInStore | E.InvalidTaskState + >; + }, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskStateTransition + >; + } + >(); + }); + }); + + describe('CompositeTaskOnStartPayload', () => { + describe('TPayload !== undefined, TStartWorkflowInput !== undefined', () => { + expectTypeOf< + T.CompositeTaskOnStartPayload< + Context, + { payload: true }, + { startWorkflowInput: true } + > + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + startTask: () => Effect.Effect< + { + enqueueStartWorkflow( + id: T.WorkflowId, + input: { startWorkflowInput: true } + ): Effect.Effect; + initializeWorkflow: (context: { + payload: true; + }) => Effect.Effect< + T.WorkflowInstance<{ payload: true }>, + E.TaskDoesNotExistInStore + >; + }, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskStateTransition + >; + } + >(); + }); + describe('TPayload !== undefined, TStartWorkflowInput === undefined', () => { + expectTypeOf< + T.CompositeTaskOnStartPayload + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + startTask: () => Effect.Effect< + { + enqueueStartWorkflow( + id: T.WorkflowId, + input?: undefined + ): Effect.Effect; + initializeWorkflow: (context: { + payload: true; + }) => Effect.Effect< + T.WorkflowInstance<{ payload: true }>, + E.TaskDoesNotExistInStore + >; + }, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskStateTransition + >; + } + >(); + }); + describe('TPayload === undefined, TStartWorkflowInput !== undefined', () => { + expectTypeOf< + T.CompositeTaskOnStartPayload< + Context, + undefined, + { startWorkflowInput: true } + > + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + startTask: () => Effect.Effect< + { + enqueueStartWorkflow( + id: T.WorkflowId, + input: { startWorkflowInput: true } + ): Effect.Effect; + initializeWorkflow: ( + context?: undefined + ) => Effect.Effect< + T.WorkflowInstance, + E.TaskDoesNotExistInStore + >; + }, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskStateTransition + >; + } + >(); + }); + describe('TPayload === undefined, TStartWorkflowInput === undefined', () => { + expectTypeOf< + T.CompositeTaskOnStartPayload + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + startTask: () => Effect.Effect< + { + enqueueStartWorkflow( + id: T.WorkflowId, + input?: undefined + ): Effect.Effect; + initializeWorkflow: ( + context?: undefined + ) => Effect.Effect< + T.WorkflowInstance, + E.TaskDoesNotExistInStore + >; + }, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskStateTransition + >; + } + >(); + }); + }); + + describe('TaskOnCompletePayload', () => { + expectTypeOf>().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + completeTask: () => Effect.Effect< + void, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskState + | E.WorkflowDoesNotExist + | E.WorkItemDoesNotExist + | E.EndConditionDoesNotExist + | E.InvalidTaskStateTransition + | E.InvalidWorkflowStateTransition + | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('TaskOnCancelPayload', () => { + expectTypeOf>().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + cancelTask: () => Effect.Effect< + void, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskState + | E.WorkflowDoesNotExist + | E.WorkItemDoesNotExist + | E.EndConditionDoesNotExist + | E.InvalidTaskStateTransition + | E.InvalidWorkflowStateTransition + | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('TaskOnFailPayload', () => { + expectTypeOf>().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + failTask: () => Effect.Effect< + void, + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.ConditionDoesNotExist + | E.ConditionDoesNotExistInStore + | E.InvalidTaskState + | E.WorkflowDoesNotExist + | E.WorkItemDoesNotExist + | E.EndConditionDoesNotExist + | E.InvalidTaskStateTransition + | E.InvalidWorkflowStateTransition + | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('TaskActivities', () => { + expectTypeOf>().toEqualTypeOf<{ + onDisable: (payload: T.TaskOnDisablePayload) => T.UnknownEffect; + onEnable: (payload: T.TaskOnEnablePayload) => T.UnknownEffect; + onStart: ( + payload: T.TaskOnStartPayload, + input?: any + ) => T.UnknownEffect; + onComplete: ( + payload: T.TaskOnCompletePayload + ) => T.UnknownEffect; + onCancel: (payload: T.TaskOnCancelPayload) => T.UnknownEffect; + onFail: (payload: T.TaskOnFailPayload) => T.UnknownEffect; + }>(); + }); + + describe('CompositeTaskActivities', () => { + expectTypeOf>().branded.toEqualTypeOf<{ + onDisable: (payload: T.TaskOnDisablePayload) => T.UnknownEffect; + onEnable: (payload: T.TaskOnEnablePayload) => T.UnknownEffect; + onStart: ( + payload: T.CompositeTaskOnStartPayload, + input?: any + ) => T.UnknownEffect; + onComplete: ( + payload: T.TaskOnCompletePayload + ) => T.UnknownEffect; + onCancel: (payload: T.TaskOnCancelPayload) => T.UnknownEffect; + onFail: (payload: T.TaskOnFailPayload) => T.UnknownEffect; + }>(); + }); + + describe('WorkItemOnStartPayload', () => { + describe('TOnCompleteInput !== undefined, T.OnCancelInput !== undefined, TOnFailInput !== undefined', () => { + expectTypeOf< + T.WorkItemOnStartPayload< + Context, + { payload: true }, + { onCompleteInput: true }, + { onCancelInput: true }, + { onFailInput: true } + > + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + getWorkItem: () => Effect.Effect< + T.WorkItemInstance<{ payload: true }>, + E.WorkItemDoesNotExist | E.TaskDoesNotExistInStore + >; + updateWorkItemPayload: (payload: { + payload: true; + }) => Effect.Effect; + startWorkItem: () => Effect.Effect< + { + enqueueCompleteWorkItem(input: { + onCompleteInput: true; + }): Effect.Effect; + enqueueCancelWorkItem(input: { + onCancelInput: true; + }): Effect.Effect; + enqueueFailWorkItem(input: { + onFailInput: true; + }): Effect.Effect; + }, + E.WorkItemDoesNotExist | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('TOnCompleteInput === undefined, T.OnCancelInput !== undefined, TOnFailInput !== undefined', () => { + expectTypeOf< + T.WorkItemOnStartPayload< + Context, + { payload: true }, + undefined, + { onCancelInput: true }, + { onFailInput: true } + > + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + getWorkItem: () => Effect.Effect< + T.WorkItemInstance<{ payload: true }>, + E.WorkItemDoesNotExist | E.TaskDoesNotExistInStore + >; + updateWorkItemPayload: (payload: { + payload: true; + }) => Effect.Effect; + startWorkItem: () => Effect.Effect< + { + enqueueCompleteWorkItem(input?: undefined): Effect.Effect; + enqueueCancelWorkItem(input: { + onCancelInput: true; + }): Effect.Effect; + enqueueFailWorkItem(input: { + onFailInput: true; + }): Effect.Effect; + }, + E.WorkItemDoesNotExist | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('TOnCompleteInput !== undefined, T.OnCancelInput === undefined, TOnFailInput !== undefined', () => { + expectTypeOf< + T.WorkItemOnStartPayload< + Context, + { payload: true }, + { onCompleteInput: true }, + undefined, + { onFailInput: true } + > + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + getWorkItem: () => Effect.Effect< + T.WorkItemInstance<{ payload: true }>, + E.WorkItemDoesNotExist | E.TaskDoesNotExistInStore + >; + updateWorkItemPayload: (payload: { + payload: true; + }) => Effect.Effect; + startWorkItem: () => Effect.Effect< + { + enqueueCompleteWorkItem(input: { + onCompleteInput: true; + }): Effect.Effect; + enqueueCancelWorkItem(input?: undefined): Effect.Effect; + enqueueFailWorkItem(input: { + onFailInput: true; + }): Effect.Effect; + }, + E.WorkItemDoesNotExist | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('TOnCompleteInput !== undefined, T.OnCancelInput !== undefined, TOnFailInput === undefined', () => { + expectTypeOf< + T.WorkItemOnStartPayload< + Context, + { payload: true }, + { onCompleteInput: true }, + { onCancelInput: true }, + undefined + > + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + getWorkItem: () => Effect.Effect< + T.WorkItemInstance<{ payload: true }>, + E.WorkItemDoesNotExist | E.TaskDoesNotExistInStore + >; + updateWorkItemPayload: (payload: { + payload: true; + }) => Effect.Effect; + startWorkItem: () => Effect.Effect< + { + enqueueCompleteWorkItem(input: { + onCompleteInput: true; + }): Effect.Effect; + enqueueCancelWorkItem(input: { + onCancelInput: true; + }): Effect.Effect; + enqueueFailWorkItem(input?: undefined): Effect.Effect; + }, + E.WorkItemDoesNotExist | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('TOnCompleteInput === undefined, T.OnCancelInput === undefined, TOnFailInput === undefined', () => { + expectTypeOf< + T.WorkItemOnStartPayload< + Context, + { payload: true }, + undefined, + undefined, + undefined + > + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + getWorkItem: () => Effect.Effect< + T.WorkItemInstance<{ payload: true }>, + E.WorkItemDoesNotExist | E.TaskDoesNotExistInStore + >; + updateWorkItemPayload: (payload: { + payload: true; + }) => Effect.Effect; + startWorkItem: () => Effect.Effect< + { + enqueueCompleteWorkItem(input?: undefined): Effect.Effect; + enqueueCancelWorkItem(input?: undefined): Effect.Effect; + enqueueFailWorkItem(input?: undefined): Effect.Effect; + }, + E.WorkItemDoesNotExist | E.InvalidWorkItemTransition + >; + } + >(); + }); + }); + + describe('WorkItemOnCompletePayload', () => { + expectTypeOf< + T.WorkItemOnCompletePayload + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + getWorkItem(): Effect.Effect< + T.WorkItemInstance<{ payload: true }>, + E.WorkItemDoesNotExist | E.TaskDoesNotExistInStore + >; + updateWorkItemPayload: (workItemPayload: { + payload: true; + }) => Effect.Effect; + completeWorkItem: () => Effect.Effect< + void, + E.WorkItemDoesNotExist | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('WorkItemOnCancelPayload', () => { + expectTypeOf< + T.WorkItemOnCancelPayload + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + getWorkItem(): Effect.Effect< + T.WorkItemInstance<{ payload: true }>, + E.WorkItemDoesNotExist | E.TaskDoesNotExistInStore + >; + updateWorkItemPayload: (workItemPayload: { + payload: true; + }) => Effect.Effect; + cancelWorkItem: () => Effect.Effect< + void, + E.WorkItemDoesNotExist | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('WorkItemOnFailPayload', () => { + expectTypeOf< + T.WorkItemOnFailPayload + >().toEqualTypeOf< + T.DefaultTaskOrWorkItemActivityPayload & { + getWorkItem(): Effect.Effect< + T.WorkItemInstance<{ payload: true }>, + E.WorkItemDoesNotExist | E.TaskDoesNotExistInStore + >; + updateWorkItemPayload: (workItemPayload: { + payload: true; + }) => Effect.Effect; + failWorkItem: () => Effect.Effect< + void, + E.WorkItemDoesNotExist | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('WorkItemActivities', () => { + expectTypeOf< + T.WorkItemActivities + >().toEqualTypeOf<{ + onStart: ( + payload: T.WorkItemOnStartPayload< + Context, + { payload: true }, + any, + any, + any + >, + input?: any + ) => T.UnknownEffect; + onComplete: ( + payload: T.WorkItemOnCompletePayload, + input?: any + ) => T.UnknownEffect; + onCancel: ( + payload: T.WorkItemOnCancelPayload, + input?: any + ) => T.UnknownEffect; + onFail: ( + payload: T.WorkItemOnFailPayload, + input?: any + ) => T.UnknownEffect; + }>(); + }); + + describe('ShouldTaskCompleteFn', () => { + expectTypeOf< + T.ShouldTaskCompleteFn< + Context, + { workItemPayload: true }, + { R: true }, + { E: true } + > + >().toEqualTypeOf< + (payload: { + getWorkflowContext: () => Effect.Effect; + workItems: T.WorkItemInstance<{ workItemPayload: true }>[]; + }) => Effect.Effect + >(); + }); + + describe('ShouldTaskFailFn', () => { + expectTypeOf< + T.ShouldTaskFailFn< + Context, + { workItemPayload: true }, + { R: true }, + { E: true } + > + >().toEqualTypeOf< + (payload: { + getWorkflowContext: () => Effect.Effect; + workItems: T.WorkItemInstance<{ workItemPayload: true }>[]; + }) => Effect.Effect + >(); + }); + + describe('ShouldCompositeTaskCompleteFn', () => { + expectTypeOf< + T.ShouldCompositeTaskCompleteFn< + Context, + { childWorkflowContext: true }, + { R: true }, + { E: true } + > + >().toEqualTypeOf< + (payload: { + getWorkflowContext: () => Effect.Effect; + workflows: T.WorkflowInstance<{ childWorkflowContext: true }>[]; + }) => Effect.Effect + >(); + }); + + describe('ShouldCompositeTaskFailFn', () => { + expectTypeOf< + T.ShouldCompositeTaskFailFn< + Context, + { childWorkflowContext: true }, + { R: true }, + { E: true } + > + >().toEqualTypeOf< + (payload: { + getWorkflowContext: () => Effect.Effect; + workflows: T.WorkflowInstance<{ childWorkflowContext: true }>[]; + }) => Effect.Effect + >(); + }); + + describe('DefaultWorkflowActivityPayload', () => { + describe('TParentWorkflowContext !== never', () => { + expectTypeOf< + T.DefaultWorkflowActivityPayload< + Context, + { parentWorkflowContext: true } + > + >().toEqualTypeOf<{ + getParentWorkflowContext: () => Effect.Effect< + { parentWorkflowContext: true }, + E.ParentWorkflowDoesNotExist | E.WorkflowDoesNotExist + >; + updateParentWorkflowContext: ( + context: + | { parentWorkflowContext: true } + | ((context: { parentWorkflowContext: true }) => { + parentWorkflowContext: true; + }) + ) => Effect.Effect< + void, + E.ParentWorkflowDoesNotExist | E.WorkflowDoesNotExist + >; + getWorkflowContext: () => Effect.Effect< + Context, + E.WorkflowDoesNotExist + >; + updateWorkflowContext: T.UpdateWorkflowContext; + }>(); + }); + + describe('TParentWorkflowContext === never', () => { + expectTypeOf< + T.DefaultWorkflowActivityPayload + >().toEqualTypeOf<{ + getParentWorkflowContext: never; + updateParentWorkflowContext: never; + getWorkflowContext: () => Effect.Effect< + Context, + E.WorkflowDoesNotExist + >; + updateWorkflowContext: T.UpdateWorkflowContext; + }>(); + }); + }); + + describe('WorkflowOnStartPayload', () => { + expectTypeOf< + T.WorkflowOnStartPayload + >().toEqualTypeOf< + T.DefaultWorkflowActivityPayload< + Context, + { parentWorkflowContext: true } + > & { + startWorkflow: () => Effect.Effect< + void, + | E.ConditionDoesNotExist + | E.WorkflowDoesNotExist + | E.StartConditionDoesNotExist + | E.InvalidWorkflowStateTransition + | E.ConditionDoesNotExistInStore + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.InvalidTaskStateTransition + >; + } + >(); + }); + + describe('WorkflowOnCompletePayload', () => { + expectTypeOf< + T.WorkflowOnCompletePayload + >().toEqualTypeOf< + T.DefaultWorkflowActivityPayload< + Context, + { parentWorkflowContext: true } + > & { + completeWorkflow: () => Effect.Effect< + void, + | E.ConditionDoesNotExist + | E.WorkflowDoesNotExist + | E.InvalidWorkflowStateTransition + | E.ConditionDoesNotExistInStore + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.InvalidTaskStateTransition + | E.InvalidTaskState + | E.EndConditionDoesNotExist + | E.WorkItemDoesNotExist + | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('WorkflowOnCancelPayload', () => { + expectTypeOf< + T.WorkflowOnCancelPayload + >().toEqualTypeOf< + T.DefaultWorkflowActivityPayload< + Context, + { parentWorkflowContext: true } + > & { + cancelWorkflow: () => Effect.Effect< + void, + | E.ConditionDoesNotExist + | E.WorkflowDoesNotExist + | E.InvalidWorkflowStateTransition + | E.ConditionDoesNotExistInStore + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.InvalidTaskStateTransition + | E.InvalidTaskState + | E.EndConditionDoesNotExist + | E.WorkItemDoesNotExist + | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('WorkflowOnFailPayload', () => { + expectTypeOf< + T.WorkflowOnFailPayload + >().toEqualTypeOf< + T.DefaultWorkflowActivityPayload< + Context, + { parentWorkflowContext: true } + > & { + failWorkflow: () => Effect.Effect< + void, + | E.ConditionDoesNotExist + | E.WorkflowDoesNotExist + | E.InvalidWorkflowStateTransition + | E.ConditionDoesNotExistInStore + | E.TaskDoesNotExist + | E.TaskDoesNotExistInStore + | E.InvalidTaskStateTransition + | E.InvalidTaskState + | E.EndConditionDoesNotExist + | E.WorkItemDoesNotExist + | E.InvalidWorkItemTransition + >; + } + >(); + }); + + describe('WorkflowActivities', () => { + expectTypeOf< + T.WorkflowActivities + >().toEqualTypeOf<{ + onStart: ( + payload: T.WorkflowOnStartPayload< + Context, + { parentWorkflowContext: true } + >, + input?: any + ) => T.UnknownEffect; + onComplete: ( + payload: T.WorkflowOnCompletePayload< + Context, + { parentWorkflowContext: true } + >, + input?: any + ) => T.UnknownEffect; + onCancel: ( + payload: T.WorkflowOnCancelPayload< + Context, + { parentWorkflowContext: true } + >, + input?: any + ) => T.UnknownEffect; + onFail: ( + payload: T.WorkflowOnFailPayload< + Context, + { parentWorkflowContext: true } + >, + input?: any + ) => T.UnknownEffect; + }>(); + }); +}); diff --git a/src/types.ts b/src/types.ts index fa499b9..fd454e8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,12 +1,4 @@ import { Brand, Context, Effect } from 'effect'; - -import { AnyCompositeTaskBuilder } from './builder/CompositeTaskBuilder.js'; -import { - ConditionFlowBuilder, - OrXorTaskFlowBuilder, - TaskFlowBuilder, -} from './builder/FlowBuilder.js'; -import { AnyTaskBuilder } from './builder/TaskBuilder.js'; import { ConditionDoesNotExist, ConditionDoesNotExistInStore, @@ -22,6 +14,14 @@ import { WorkItemDoesNotExist, WorkflowDoesNotExist, } from './errors.js'; +import { + ConditionFlowBuilder, + OrXorTaskFlowBuilder, + TaskFlowBuilder, +} from './builder/FlowBuilder.js'; + +import { AnyCompositeTaskBuilder } from './builder/CompositeTaskBuilder.js'; +import { AnyTaskBuilder } from './builder/TaskBuilder.js'; export type UnknownEffect = Effect.Effect; @@ -67,7 +67,7 @@ export interface WorkflowBuilderDefinition { }; } -type UpdateWorkflowContext = ( +export type UpdateWorkflowContext = ( contextOrUpdater: TContext | ((context: TContext) => TContext) ) => Effect.Effect; @@ -129,15 +129,15 @@ export type TaskOnStartPayload< export type CompositeTaskOnStartPayload< TContext, TPayload = unknown, - TStartWorkItemInput = unknown + TStartWorkflowInput = unknown > = DefaultTaskOrWorkItemActivityPayload & { startTask: () => Effect.Effect< { enqueueStartWorkflow( id: WorkflowId, - ...input: undefined extends TStartWorkItemInput - ? [TStartWorkItemInput?] - : [TStartWorkItemInput] + ...input: undefined extends TStartWorkflowInput + ? [TStartWorkflowInput?] + : [TStartWorkflowInput] ): Effect.Effect; initializeWorkflow: ( ...context: undefined extends TPayload ? [TPayload?] : [TPayload] @@ -550,9 +550,9 @@ export type ShouldTaskCompleteFn< R = unknown, E = unknown > = (payload: { - getWorkflowContext: () => Effect.Effect; + getWorkflowContext: () => Effect.Effect; workItems: WorkItemInstance[]; -}) => Effect.Effect; +}) => Effect.Effect; export type ShouldTaskFailFn< TContext, @@ -606,6 +606,7 @@ export interface StateChangeItem< TTask >; } + export interface StateChangeLogger { log: (item: StateChangeItem) => void; drain: () => StateChangeItem[]; @@ -634,13 +635,13 @@ export interface DefaultWorkflowActivityPayload< TContext, TParentWorkflowContext > { - getParentWorkflowContext: TParentWorkflowContext extends never + getParentWorkflowContext: [TParentWorkflowContext] extends [never] ? never : () => Effect.Effect< TParentWorkflowContext, ParentWorkflowDoesNotExist | WorkflowDoesNotExist >; - updateParentWorkflowContext: TParentWorkflowContext extends never + updateParentWorkflowContext: [TParentWorkflowContext] extends [never] ? never : ( context: