BUILD / FRAMEWORK INTEGRATIONS
Your framework, unchanged.
Use a small application-level adapter to bring engine snapshots into your existing reactive model.
A headless integration
React, Vue, and Angular dependencies belong to your application, never to the core package. The examples below adapt the same public IEngine interface. They are patterns to copy and extend—not exports from @newvexa/workify.
Start runs on explicit actions, not during rendering, on module import, or automatically inside a lifecycle effect. Keep an engine stable for its view or consumer.
Framework adapters
import { useCallback, useEffect, useSyncExternalStore } from "react";
import type { IEngine } from "@newvexa/workify";
export function useWorkflow(engine: IEngine) {
const subscribe = useCallback(
(listener: () => void) => engine.subscribe(listener), [engine],
);
const getSnapshot = useCallback(() => engine.getSnapshot(), [engine]);
useEffect(() => {
const stop = engine.onEvent((event) => {
if (event.type === "run.finished") console.log(event.status);
});
return stop;
}, [engine]);
return useSyncExternalStore(subscribe, getSnapshot);
}
Use the engine as an external store. Subscribe to snapshots with a custom hook and clean up execution event listeners with useEffect. Integration guide
In Vue, call the composable inside setup() or an active effect scope. Read state.value.status in script; templates unwrap the ref. onScopeDispose removes the state observer.
React lifecycle & events
The React hook uses useSyncExternalStore for immutable snapshots and useEffect to subscribe to detailed execution events. Both APIs are cleaned up when the consumer changes or unmounts. Keep the instance stable:
import { useState } from "react";
import { createWorkflowEngine } from "./workflow";
import { useWorkflow } from "./useWorkflow";
// Inside your component:
const [engine] = useState(() => createWorkflowEngine());
const snapshot = useWorkflow(engine);
// Start explicitly from a button handler:
// onClick={() => void engine.run(21)}
Angular dependency injection
Provide both the service and engine at the component/view level. Import the quick-start factory and the token/service from your application files, then use the provider array in the component’s providers metadata.
const workflowProviders = [
WorkflowService,
{ provide: WORKFLOW_ENGINE, useFactory: createWorkflowEngine },
];
// Use workflowProviders in your component's providers.
The service bridges subscriptions to a signal. DestroyRef removes the observer on view destruction; it does not automatically stop an owned run.
Lifecycle & cancellation
Unsubscribing and cancelling are different operations. On cleanup, remove listeners and abort any run the view owns. Cooperative cancellation still waits for started handlers to settle.
const controller = new AbortController();
const pending = engine.run(21, { signal: controller.signal });
controller.abort();
const result = await pending;
console.log(result.status); // "cancelled"
For complete run/cancel/error handling, read the shipped framework examples: