@rytejs/react 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -37,13 +37,13 @@ function createWorkflowClient(transport) {
|
|
|
37
37
|
if (existing) {
|
|
38
38
|
return existing;
|
|
39
39
|
}
|
|
40
|
-
const store = createRemoteStore(transport, definition, id);
|
|
40
|
+
const store = createRemoteStore(transport, definition, id, () => cache.delete(cacheKey));
|
|
41
41
|
cache.set(cacheKey, store);
|
|
42
42
|
return store;
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
|
-
function createRemoteStore(transport, definition, id) {
|
|
46
|
+
function createRemoteStore(transport, definition, id, onDispose) {
|
|
47
47
|
let workflow = null;
|
|
48
48
|
let version = 0;
|
|
49
49
|
let isLoading = true;
|
|
@@ -171,6 +171,7 @@ function createRemoteStore(transport, definition, id) {
|
|
|
171
171
|
cleanup() {
|
|
172
172
|
disposed = true;
|
|
173
173
|
subscription.unsubscribe();
|
|
174
|
+
onDispose();
|
|
174
175
|
}
|
|
175
176
|
};
|
|
176
177
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/context.ts","../src/use-workflow.ts","../src/store.ts"],"sourcesContent":["export { createWorkflowClient } from \"./client.js\";\nexport { createWorkflowContext } from \"./context.js\";\nexport { createWorkflowStore } from \"./store.js\";\nexport type {\n\tBroadcastMessage,\n\tTransport,\n\tTransportError,\n\tTransportResult,\n\tTransportSubscription,\n} from \"./transport.js\";\nexport type {\n\tUseWorkflowReturn,\n\tWorkflowStore,\n\tWorkflowStoreOptions,\n\tWorkflowStoreSnapshot,\n} from \"./types.js\";\nexport { useWorkflow } from \"./use-workflow.js\";\n","import type {\n\tCommandNames,\n\tCommandPayload,\n\tDispatchResult,\n\tPipelineError,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowDefinition,\n} from \"@rytejs/core\";\nimport type { BroadcastMessage, Transport } from \"./transport.js\";\nimport type { WorkflowStore, WorkflowStoreSnapshot } from \"./types.js\";\n\nexport function createWorkflowClient(transport: Transport) {\n\t// biome-ignore lint/suspicious/noExplicitAny: cache stores keyed by string, values are type-erased WorkflowStore instances\n\tconst cache = new Map<string, WorkflowStore<any>>();\n\n\treturn {\n\t\tconnect<TConfig extends WorkflowConfig>(\n\t\t\tdefinition: WorkflowDefinition<TConfig>,\n\t\t\tid: string,\n\t\t): WorkflowStore<TConfig> {\n\t\t\tconst cacheKey = `${definition.name}:${id}`;\n\t\t\tconst existing = cache.get(cacheKey);\n\t\t\tif (existing) {\n\t\t\t\treturn existing as WorkflowStore<TConfig>;\n\t\t\t}\n\n\t\t\tconst store = createRemoteStore(transport, definition, id);\n\t\t\tcache.set(cacheKey, store);\n\t\t\treturn store;\n\t\t},\n\t};\n}\n\nfunction createRemoteStore<TConfig extends WorkflowConfig>(\n\ttransport: Transport,\n\tdefinition: WorkflowDefinition<TConfig>,\n\tid: string,\n): WorkflowStore<TConfig> {\n\tlet workflow: Workflow<TConfig> | null = null;\n\tlet version = 0;\n\tlet isLoading = true;\n\tlet isDispatching = false;\n\tlet error: PipelineError<TConfig> | null = null;\n\tlet disposed = false;\n\n\tconst listeners = new Set<() => void>();\n\n\tlet snapshot: WorkflowStoreSnapshot<TConfig> = {\n\t\tworkflow,\n\t\tisLoading,\n\t\tisDispatching,\n\t\terror,\n\t};\n\n\tfunction notify() {\n\t\tif (disposed) return;\n\t\tsnapshot = { workflow, isLoading, isDispatching, error };\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t}\n\n\t// Eagerly load\n\ttransport\n\t\t.load(id)\n\t\t.then((result) => {\n\t\t\tif (disposed) return;\n\t\t\tif (result !== null) {\n\t\t\t\tconst restored = definition.deserialize(result.snapshot);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\tworkflow = restored.workflow;\n\t\t\t\t\tversion = result.version;\n\t\t\t\t}\n\t\t\t}\n\t\t\tisLoading = false;\n\t\t\tnotify();\n\t\t})\n\t\t.catch((err: unknown) => {\n\t\t\tif (disposed) return;\n\t\t\terror = {\n\t\t\t\tcategory: \"unexpected\",\n\t\t\t\terror: err,\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: TransportError mapped to PipelineError shape for interface conformance\n\t\t\t} as any;\n\t\t\tisLoading = false;\n\t\t\tnotify();\n\t\t});\n\n\t// Subscribe to live broadcasts\n\tconst subscription = transport.subscribe(id, (message: BroadcastMessage) => {\n\t\tif (disposed) return;\n\t\tconst restored = definition.deserialize(message.snapshot);\n\t\tif (restored.ok) {\n\t\t\tworkflow = restored.workflow;\n\t\t\tversion = message.version;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t}\n\t});\n\n\tconst dispatch = async <C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\tpayload: CommandPayload<TConfig, C>,\n\t): Promise<DispatchResult<TConfig>> => {\n\t\tif (isLoading) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\terror: new Error(\"Cannot dispatch while loading\"),\n\t\t\t\t\tmessage: \"Cannot dispatch while loading\",\n\t\t\t\t},\n\t\t\t} as DispatchResult<TConfig>;\n\t\t}\n\n\t\tisDispatching = true;\n\t\tnotify();\n\n\t\ttry {\n\t\t\tconst result = await transport.dispatch(id, { type: command as string, payload }, version);\n\n\t\t\tif (result.ok) {\n\t\t\t\tconst restored = definition.deserialize(result.snapshot);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\tworkflow = restored.workflow;\n\t\t\t\t\tversion = result.version;\n\t\t\t\t\terror = null;\n\t\t\t\t\tisDispatching = false;\n\t\t\t\t\tnotify();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tworkflow: restored.workflow,\n\t\t\t\t\t\tevents: result.events,\n\t\t\t\t\t} as DispatchResult<TConfig>;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Error path\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: TransportError mapped to PipelineError shape\n\t\t\terror = (result.ok ? null : result.error) as any;\n\t\t\tisDispatching = false;\n\t\t\tnotify();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: error ?? {\n\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\terror: new Error(\"Transport error\"),\n\t\t\t\t\tmessage: \"Transport error\",\n\t\t\t\t},\n\t\t\t} as DispatchResult<TConfig>;\n\t\t} catch (err: unknown) {\n\t\t\terror = {\n\t\t\t\tcategory: \"unexpected\",\n\t\t\t\terror: err,\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: network error mapped to PipelineError shape\n\t\t\t} as any;\n\t\t\tisDispatching = false;\n\t\t\tnotify();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: error is always assigned in the catch block above\n\t\t\t\terror: error!,\n\t\t\t} as DispatchResult<TConfig>;\n\t\t}\n\t};\n\n\treturn {\n\t\tgetWorkflow: () => workflow,\n\t\tgetSnapshot: () => snapshot,\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tdispatch,\n\t\tsetWorkflow: (newWorkflow) => {\n\t\t\tworkflow = newWorkflow;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t},\n\t\tcleanup() {\n\t\t\tdisposed = true;\n\t\t\tsubscription.unsubscribe();\n\t\t},\n\t};\n}\n","import type { Workflow, WorkflowConfig, WorkflowDefinition } from \"@rytejs/core\";\nimport type { ReactNode } from \"react\";\nimport { createContext, createElement, useContext } from \"react\";\nimport type { UseWorkflowReturn, WorkflowStore } from \"./types.js\";\nimport { useWorkflow } from \"./use-workflow.js\";\n\nexport function createWorkflowContext<TConfig extends WorkflowConfig>(\n\t_definition: WorkflowDefinition<TConfig>,\n): {\n\tProvider: (props: { store: WorkflowStore<TConfig>; children?: ReactNode }) => ReactNode;\n\tuseWorkflow: {\n\t\t(): UseWorkflowReturn<TConfig>;\n\t\t<R>(selector: (workflow: Workflow<TConfig>) => R, equalityFn?: (a: R, b: R) => boolean): R;\n\t};\n} {\n\tconst StoreContext = createContext<WorkflowStore<TConfig> | null>(null);\n\n\tfunction Provider({\n\t\tstore,\n\t\tchildren,\n\t}: {\n\t\tstore: WorkflowStore<TConfig>;\n\t\tchildren?: ReactNode;\n\t}): ReactNode {\n\t\treturn createElement(StoreContext.Provider, { value: store }, children);\n\t}\n\n\tfunction useWorkflowFromContext(): UseWorkflowReturn<TConfig>;\n\tfunction useWorkflowFromContext<R>(\n\t\tselector: (workflow: Workflow<TConfig>) => R,\n\t\tequalityFn?: (a: R, b: R) => boolean,\n\t): R;\n\tfunction useWorkflowFromContext<R>(\n\t\tselector?: (workflow: Workflow<TConfig>) => R,\n\t\tequalityFn?: (a: R, b: R) => boolean,\n\t): UseWorkflowReturn<TConfig> | R {\n\t\tconst store = useContext(StoreContext);\n\t\tif (!store) {\n\t\t\tthrow new Error(\n\t\t\t\t\"useWorkflow must be used within a WorkflowProvider. \" +\n\t\t\t\t\t\"Wrap your component tree with <Provider store={...}>.\",\n\t\t\t);\n\t\t}\n\t\tif (selector) {\n\t\t\t// biome-ignore lint/correctness/useHookAtTopLevel: selector presence is stable per render — callers must not change between selector and no-selector mode\n\t\t\treturn useWorkflow(store, selector, equalityFn);\n\t\t}\n\t\t// biome-ignore lint/correctness/useHookAtTopLevel: called on the non-selector path; mutually exclusive with the branch above but stable per component lifetime\n\t\treturn useWorkflow(store);\n\t}\n\n\treturn { Provider, useWorkflow: useWorkflowFromContext };\n}\n","import type { Workflow, WorkflowConfig } from \"@rytejs/core\";\nimport { useCallback, useRef, useSyncExternalStore } from \"react\";\nimport type { UseWorkflowReturn, WorkflowStore, WorkflowStoreSnapshot } from \"./types.js\";\n\nfunction createReturn<TConfig extends WorkflowConfig>(\n\tsnapshot: WorkflowStoreSnapshot<TConfig>,\n\tdispatch: WorkflowStore<TConfig>[\"dispatch\"],\n): UseWorkflowReturn<TConfig> {\n\tconst wf = snapshot.workflow;\n\treturn {\n\t\tworkflow: wf,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: state/data are undefined when workflow is null (loading) — consumers check isLoading first\n\t\tstate: wf?.state as any,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: see above\n\t\tdata: wf?.data as any,\n\t\tisLoading: snapshot.isLoading,\n\t\tisDispatching: snapshot.isDispatching,\n\t\terror: snapshot.error,\n\t\tdispatch,\n\t\tmatch(\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t\tmatchers: Record<string, any>,\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t\tfallback?: (workflow: Workflow<TConfig> | null) => any,\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t): any {\n\t\t\tif (!wf) {\n\t\t\t\tif (fallback) return fallback(wf);\n\t\t\t\tthrow new Error(\"Cannot match on a loading workflow — check isLoading first\");\n\t\t\t}\n\t\t\tconst state = wf.state as string;\n\t\t\tconst matcher = matchers[state];\n\t\t\tif (matcher) {\n\t\t\t\treturn matcher(wf.data, wf);\n\t\t\t}\n\t\t\tif (fallback) {\n\t\t\t\treturn fallback(wf);\n\t\t\t}\n\t\t\tthrow new Error(`No match for state \"${state}\" and no fallback provided`);\n\t\t},\n\t} as UseWorkflowReturn<TConfig>;\n}\n\nexport function useWorkflow<TConfig extends WorkflowConfig>(\n\tstore: WorkflowStore<TConfig>,\n): UseWorkflowReturn<TConfig>;\nexport function useWorkflow<TConfig extends WorkflowConfig, R>(\n\tstore: WorkflowStore<TConfig>,\n\tselector: (workflow: Workflow<TConfig>) => R,\n\tequalityFn?: (a: R, b: R) => boolean,\n): R;\nexport function useWorkflow<TConfig extends WorkflowConfig, R>(\n\tstore: WorkflowStore<TConfig>,\n\tselector?: (workflow: Workflow<TConfig>) => R,\n\tequalityFn?: (a: R, b: R) => boolean,\n): UseWorkflowReturn<TConfig> | R {\n\t// Refs for selector caching — always allocated to maintain hook call order\n\tconst selectorRef = useRef(selector);\n\tconst equalityFnRef = useRef(equalityFn);\n\tconst cachedRef = useRef<R | undefined>(undefined);\n\tconst hasCachedRef = useRef(false);\n\tselectorRef.current = selector;\n\tequalityFnRef.current = equalityFn;\n\n\tconst selectorSnapshot = useCallback(() => {\n\t\tconst wf = store.getWorkflow();\n\t\tif (!wf) {\n\t\t\t// Workflow is loading — return cached value if available\n\t\t\treturn cachedRef.current;\n\t\t}\n\t\t// biome-ignore lint/style/noNonNullAssertion: selectorSnapshot is only used when selector is defined (checked at call site)\n\t\tconst next = selectorRef.current!(wf);\n\t\tconst eq = equalityFnRef.current ?? Object.is;\n\t\tif (hasCachedRef.current && eq(cachedRef.current as R, next)) {\n\t\t\treturn cachedRef.current;\n\t\t}\n\t\tcachedRef.current = next;\n\t\thasCachedRef.current = true;\n\t\treturn next;\n\t}, [store]);\n\n\t// biome-ignore lint/suspicious/noExplicitAny: return type varies by overload; TS can't narrow union of getSnapshot functions\n\tconst getSnapshot: () => any = selector ? selectorSnapshot : store.getSnapshot;\n\n\tconst result: unknown = useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n\n\tif (!selector) {\n\t\treturn createReturn(result as WorkflowStoreSnapshot<TConfig>, store.dispatch);\n\t}\n\treturn result as R;\n}\n","import type {\n\tCommandNames,\n\tCommandPayload,\n\tDispatchResult,\n\tPipelineError,\n\tStateData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowDefinition,\n} from \"@rytejs/core\";\nimport { migrate, type WorkflowRouter } from \"@rytejs/core\";\nimport type { WorkflowStore, WorkflowStoreOptions, WorkflowStoreSnapshot } from \"./types.js\";\n\nexport function createWorkflowStore<\n\tTConfig extends WorkflowConfig,\n\tTDeps,\n\tS extends StateNames<TConfig>,\n>(\n\trouter: WorkflowRouter<TConfig, TDeps>,\n\tinitialConfig: {\n\t\tstate: S;\n\t\tdata: StateData<TConfig, S>;\n\t\tid?: string;\n\t},\n\toptions?: WorkflowStoreOptions<TConfig>,\n): WorkflowStore<TConfig> {\n\tconst definition = router.definition;\n\n\tlet workflow: Workflow<TConfig> = loadOrCreate(definition, initialConfig, options);\n\tlet isDispatching = false;\n\tlet error: PipelineError<TConfig> | null = null;\n\tlet snapshot: WorkflowStoreSnapshot<TConfig> = {\n\t\tworkflow,\n\t\tisLoading: false,\n\t\tisDispatching,\n\t\terror,\n\t};\n\tconst listeners = new Set<() => void>();\n\n\tfunction notify() {\n\t\tsnapshot = { workflow, isLoading: false, isDispatching, error };\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t}\n\n\tconst dispatch = async <C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\tpayload: CommandPayload<TConfig, C>,\n\t): Promise<DispatchResult<TConfig>> => {\n\t\tisDispatching = true;\n\t\tnotify();\n\n\t\tconst result = await router.dispatch(workflow, { type: command, payload });\n\n\t\tif (result.ok) {\n\t\t\tworkflow = result.workflow;\n\t\t\terror = null;\n\t\t} else {\n\t\t\terror = result.error;\n\t\t}\n\t\tisDispatching = false;\n\t\tnotify();\n\n\t\tif (result.ok && options?.persist) {\n\t\t\tconst { key, storage } = options.persist;\n\t\t\tconst snap = definition.serialize(workflow);\n\t\t\tstorage.setItem(key, JSON.stringify(snap));\n\t\t}\n\n\t\treturn result;\n\t};\n\n\treturn {\n\t\tgetWorkflow: () => workflow,\n\t\tgetSnapshot: () => snapshot,\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tdispatch,\n\t\tsetWorkflow: (newWorkflow) => {\n\t\t\tworkflow = newWorkflow;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t},\n\t\tcleanup() {},\n\t};\n}\n\nfunction loadOrCreate<TConfig extends WorkflowConfig, S extends StateNames<TConfig>>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\tinitialConfig: { state: S; data: StateData<TConfig, S>; id?: string },\n\toptions?: WorkflowStoreOptions<TConfig>,\n): Workflow<TConfig> {\n\tif (options?.persist) {\n\t\tconst { key, storage, migrations } = options.persist;\n\t\ttry {\n\t\t\tconst stored = storage.getItem(key);\n\t\t\tif (stored) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: JSON.parse returns unknown structure from storage\n\t\t\t\tlet parsed: any = JSON.parse(stored);\n\t\t\t\tif (migrations) {\n\t\t\t\t\tconst migrated = migrate(migrations, parsed);\n\t\t\t\t\tif (migrated.ok) {\n\t\t\t\t\t\tparsed = migrated.snapshot;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn createFresh(definition, initialConfig);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst restored = definition.deserialize(parsed);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\treturn restored.workflow;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Invalid JSON or deserialize failed — fall through to create fresh\n\t\t}\n\t}\n\n\treturn createFresh(definition, initialConfig);\n}\n\nfunction createFresh<TConfig extends WorkflowConfig, S extends StateNames<TConfig>>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\tinitialConfig: { state: S; data: StateData<TConfig, S>; id?: string },\n): Workflow<TConfig> {\n\treturn definition.createWorkflow(initialConfig.id ?? crypto.randomUUID(), {\n\t\tinitialState: initialConfig.state,\n\t\tdata: initialConfig.data,\n\t});\n}\n"],"mappings":"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","names":["import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/context.ts","../src/use-workflow.ts","../src/store.ts"],"sourcesContent":["export { createWorkflowClient } from \"./client.js\";\nexport { createWorkflowContext } from \"./context.js\";\nexport { createWorkflowStore } from \"./store.js\";\nexport type {\n\tBroadcastMessage,\n\tTransport,\n\tTransportError,\n\tTransportResult,\n\tTransportSubscription,\n} from \"./transport.js\";\nexport type {\n\tUseWorkflowReturn,\n\tWorkflowStore,\n\tWorkflowStoreOptions,\n\tWorkflowStoreSnapshot,\n} from \"./types.js\";\nexport { useWorkflow } from \"./use-workflow.js\";\n","import type {\n\tCommandNames,\n\tCommandPayload,\n\tDispatchResult,\n\tPipelineError,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowDefinition,\n} from \"@rytejs/core\";\nimport type { BroadcastMessage, Transport } from \"./transport.js\";\nimport type { WorkflowStore, WorkflowStoreSnapshot } from \"./types.js\";\n\nexport function createWorkflowClient(transport: Transport) {\n\t// biome-ignore lint/suspicious/noExplicitAny: cache stores keyed by string, values are type-erased WorkflowStore instances\n\tconst cache = new Map<string, WorkflowStore<any>>();\n\n\treturn {\n\t\tconnect<TConfig extends WorkflowConfig>(\n\t\t\tdefinition: WorkflowDefinition<TConfig>,\n\t\t\tid: string,\n\t\t): WorkflowStore<TConfig> {\n\t\t\tconst cacheKey = `${definition.name}:${id}`;\n\t\t\tconst existing = cache.get(cacheKey);\n\t\t\tif (existing) {\n\t\t\t\treturn existing as WorkflowStore<TConfig>;\n\t\t\t}\n\n\t\t\tconst store = createRemoteStore(transport, definition, id, () => cache.delete(cacheKey));\n\t\t\tcache.set(cacheKey, store);\n\t\t\treturn store;\n\t\t},\n\t};\n}\n\nfunction createRemoteStore<TConfig extends WorkflowConfig>(\n\ttransport: Transport,\n\tdefinition: WorkflowDefinition<TConfig>,\n\tid: string,\n\tonDispose: () => void,\n): WorkflowStore<TConfig> {\n\tlet workflow: Workflow<TConfig> | null = null;\n\tlet version = 0;\n\tlet isLoading = true;\n\tlet isDispatching = false;\n\tlet error: PipelineError<TConfig> | null = null;\n\tlet disposed = false;\n\n\tconst listeners = new Set<() => void>();\n\n\tlet snapshot: WorkflowStoreSnapshot<TConfig> = {\n\t\tworkflow,\n\t\tisLoading,\n\t\tisDispatching,\n\t\terror,\n\t};\n\n\tfunction notify() {\n\t\tif (disposed) return;\n\t\tsnapshot = { workflow, isLoading, isDispatching, error };\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t}\n\n\t// Eagerly load\n\ttransport\n\t\t.load(id)\n\t\t.then((result) => {\n\t\t\tif (disposed) return;\n\t\t\tif (result !== null) {\n\t\t\t\tconst restored = definition.deserialize(result.snapshot);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\tworkflow = restored.workflow;\n\t\t\t\t\tversion = result.version;\n\t\t\t\t}\n\t\t\t}\n\t\t\tisLoading = false;\n\t\t\tnotify();\n\t\t})\n\t\t.catch((err: unknown) => {\n\t\t\tif (disposed) return;\n\t\t\terror = {\n\t\t\t\tcategory: \"unexpected\",\n\t\t\t\terror: err,\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: TransportError mapped to PipelineError shape for interface conformance\n\t\t\t} as any;\n\t\t\tisLoading = false;\n\t\t\tnotify();\n\t\t});\n\n\t// Subscribe to live broadcasts\n\tconst subscription = transport.subscribe(id, (message: BroadcastMessage) => {\n\t\tif (disposed) return;\n\t\tconst restored = definition.deserialize(message.snapshot);\n\t\tif (restored.ok) {\n\t\t\tworkflow = restored.workflow;\n\t\t\tversion = message.version;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t}\n\t});\n\n\tconst dispatch = async <C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\tpayload: CommandPayload<TConfig, C>,\n\t): Promise<DispatchResult<TConfig>> => {\n\t\tif (isLoading) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\terror: new Error(\"Cannot dispatch while loading\"),\n\t\t\t\t\tmessage: \"Cannot dispatch while loading\",\n\t\t\t\t},\n\t\t\t} as DispatchResult<TConfig>;\n\t\t}\n\n\t\tisDispatching = true;\n\t\tnotify();\n\n\t\ttry {\n\t\t\tconst result = await transport.dispatch(id, { type: command as string, payload }, version);\n\n\t\t\tif (result.ok) {\n\t\t\t\tconst restored = definition.deserialize(result.snapshot);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\tworkflow = restored.workflow;\n\t\t\t\t\tversion = result.version;\n\t\t\t\t\terror = null;\n\t\t\t\t\tisDispatching = false;\n\t\t\t\t\tnotify();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tworkflow: restored.workflow,\n\t\t\t\t\t\tevents: result.events,\n\t\t\t\t\t} as DispatchResult<TConfig>;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Error path\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: TransportError mapped to PipelineError shape\n\t\t\terror = (result.ok ? null : result.error) as any;\n\t\t\tisDispatching = false;\n\t\t\tnotify();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: error ?? {\n\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\terror: new Error(\"Transport error\"),\n\t\t\t\t\tmessage: \"Transport error\",\n\t\t\t\t},\n\t\t\t} as DispatchResult<TConfig>;\n\t\t} catch (err: unknown) {\n\t\t\terror = {\n\t\t\t\tcategory: \"unexpected\",\n\t\t\t\terror: err,\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: network error mapped to PipelineError shape\n\t\t\t} as any;\n\t\t\tisDispatching = false;\n\t\t\tnotify();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: error is always assigned in the catch block above\n\t\t\t\terror: error!,\n\t\t\t} as DispatchResult<TConfig>;\n\t\t}\n\t};\n\n\treturn {\n\t\tgetWorkflow: () => workflow,\n\t\tgetSnapshot: () => snapshot,\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tdispatch,\n\t\tsetWorkflow: (newWorkflow) => {\n\t\t\tworkflow = newWorkflow;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t},\n\t\tcleanup() {\n\t\t\tdisposed = true;\n\t\t\tsubscription.unsubscribe();\n\t\t\tonDispose();\n\t\t},\n\t};\n}\n","import type { Workflow, WorkflowConfig, WorkflowDefinition } from \"@rytejs/core\";\nimport type { ReactNode } from \"react\";\nimport { createContext, createElement, useContext } from \"react\";\nimport type { UseWorkflowReturn, WorkflowStore } from \"./types.js\";\nimport { useWorkflow } from \"./use-workflow.js\";\n\nexport function createWorkflowContext<TConfig extends WorkflowConfig>(\n\t_definition: WorkflowDefinition<TConfig>,\n): {\n\tProvider: (props: { store: WorkflowStore<TConfig>; children?: ReactNode }) => ReactNode;\n\tuseWorkflow: {\n\t\t(): UseWorkflowReturn<TConfig>;\n\t\t<R>(selector: (workflow: Workflow<TConfig>) => R, equalityFn?: (a: R, b: R) => boolean): R;\n\t};\n} {\n\tconst StoreContext = createContext<WorkflowStore<TConfig> | null>(null);\n\n\tfunction Provider({\n\t\tstore,\n\t\tchildren,\n\t}: {\n\t\tstore: WorkflowStore<TConfig>;\n\t\tchildren?: ReactNode;\n\t}): ReactNode {\n\t\treturn createElement(StoreContext.Provider, { value: store }, children);\n\t}\n\n\tfunction useWorkflowFromContext(): UseWorkflowReturn<TConfig>;\n\tfunction useWorkflowFromContext<R>(\n\t\tselector: (workflow: Workflow<TConfig>) => R,\n\t\tequalityFn?: (a: R, b: R) => boolean,\n\t): R;\n\tfunction useWorkflowFromContext<R>(\n\t\tselector?: (workflow: Workflow<TConfig>) => R,\n\t\tequalityFn?: (a: R, b: R) => boolean,\n\t): UseWorkflowReturn<TConfig> | R {\n\t\tconst store = useContext(StoreContext);\n\t\tif (!store) {\n\t\t\tthrow new Error(\n\t\t\t\t\"useWorkflow must be used within a WorkflowProvider. \" +\n\t\t\t\t\t\"Wrap your component tree with <Provider store={...}>.\",\n\t\t\t);\n\t\t}\n\t\tif (selector) {\n\t\t\t// biome-ignore lint/correctness/useHookAtTopLevel: selector presence is stable per render — callers must not change between selector and no-selector mode\n\t\t\treturn useWorkflow(store, selector, equalityFn);\n\t\t}\n\t\t// biome-ignore lint/correctness/useHookAtTopLevel: called on the non-selector path; mutually exclusive with the branch above but stable per component lifetime\n\t\treturn useWorkflow(store);\n\t}\n\n\treturn { Provider, useWorkflow: useWorkflowFromContext };\n}\n","import type { Workflow, WorkflowConfig } from \"@rytejs/core\";\nimport { useCallback, useRef, useSyncExternalStore } from \"react\";\nimport type { UseWorkflowReturn, WorkflowStore, WorkflowStoreSnapshot } from \"./types.js\";\n\nfunction createReturn<TConfig extends WorkflowConfig>(\n\tsnapshot: WorkflowStoreSnapshot<TConfig>,\n\tdispatch: WorkflowStore<TConfig>[\"dispatch\"],\n): UseWorkflowReturn<TConfig> {\n\tconst wf = snapshot.workflow;\n\treturn {\n\t\tworkflow: wf,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: state/data are undefined when workflow is null (loading) — consumers check isLoading first\n\t\tstate: wf?.state as any,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: see above\n\t\tdata: wf?.data as any,\n\t\tisLoading: snapshot.isLoading,\n\t\tisDispatching: snapshot.isDispatching,\n\t\terror: snapshot.error,\n\t\tdispatch,\n\t\tmatch(\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t\tmatchers: Record<string, any>,\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t\tfallback?: (workflow: Workflow<TConfig> | null) => any,\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t): any {\n\t\t\tif (!wf) {\n\t\t\t\tif (fallback) return fallback(wf);\n\t\t\t\tthrow new Error(\"Cannot match on a loading workflow — check isLoading first\");\n\t\t\t}\n\t\t\tconst state = wf.state as string;\n\t\t\tconst matcher = matchers[state];\n\t\t\tif (matcher) {\n\t\t\t\treturn matcher(wf.data, wf);\n\t\t\t}\n\t\t\tif (fallback) {\n\t\t\t\treturn fallback(wf);\n\t\t\t}\n\t\t\tthrow new Error(`No match for state \"${state}\" and no fallback provided`);\n\t\t},\n\t} as UseWorkflowReturn<TConfig>;\n}\n\nexport function useWorkflow<TConfig extends WorkflowConfig>(\n\tstore: WorkflowStore<TConfig>,\n): UseWorkflowReturn<TConfig>;\nexport function useWorkflow<TConfig extends WorkflowConfig, R>(\n\tstore: WorkflowStore<TConfig>,\n\tselector: (workflow: Workflow<TConfig>) => R,\n\tequalityFn?: (a: R, b: R) => boolean,\n): R;\nexport function useWorkflow<TConfig extends WorkflowConfig, R>(\n\tstore: WorkflowStore<TConfig>,\n\tselector?: (workflow: Workflow<TConfig>) => R,\n\tequalityFn?: (a: R, b: R) => boolean,\n): UseWorkflowReturn<TConfig> | R {\n\t// Refs for selector caching — always allocated to maintain hook call order\n\tconst selectorRef = useRef(selector);\n\tconst equalityFnRef = useRef(equalityFn);\n\tconst cachedRef = useRef<R | undefined>(undefined);\n\tconst hasCachedRef = useRef(false);\n\tselectorRef.current = selector;\n\tequalityFnRef.current = equalityFn;\n\n\tconst selectorSnapshot = useCallback(() => {\n\t\tconst wf = store.getWorkflow();\n\t\tif (!wf) {\n\t\t\t// Workflow is loading — return cached value if available\n\t\t\treturn cachedRef.current;\n\t\t}\n\t\t// biome-ignore lint/style/noNonNullAssertion: selectorSnapshot is only used when selector is defined (checked at call site)\n\t\tconst next = selectorRef.current!(wf);\n\t\tconst eq = equalityFnRef.current ?? Object.is;\n\t\tif (hasCachedRef.current && eq(cachedRef.current as R, next)) {\n\t\t\treturn cachedRef.current;\n\t\t}\n\t\tcachedRef.current = next;\n\t\thasCachedRef.current = true;\n\t\treturn next;\n\t}, [store]);\n\n\t// biome-ignore lint/suspicious/noExplicitAny: return type varies by overload; TS can't narrow union of getSnapshot functions\n\tconst getSnapshot: () => any = selector ? selectorSnapshot : store.getSnapshot;\n\n\tconst result: unknown = useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n\n\tif (!selector) {\n\t\treturn createReturn(result as WorkflowStoreSnapshot<TConfig>, store.dispatch);\n\t}\n\treturn result as R;\n}\n","import type {\n\tCommandNames,\n\tCommandPayload,\n\tDispatchResult,\n\tPipelineError,\n\tStateData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowDefinition,\n} from \"@rytejs/core\";\nimport { migrate, type WorkflowRouter } from \"@rytejs/core\";\nimport type { WorkflowStore, WorkflowStoreOptions, WorkflowStoreSnapshot } from \"./types.js\";\n\nexport function createWorkflowStore<\n\tTConfig extends WorkflowConfig,\n\tTDeps,\n\tS extends StateNames<TConfig>,\n>(\n\trouter: WorkflowRouter<TConfig, TDeps>,\n\tinitialConfig: {\n\t\tstate: S;\n\t\tdata: StateData<TConfig, S>;\n\t\tid?: string;\n\t},\n\toptions?: WorkflowStoreOptions<TConfig>,\n): WorkflowStore<TConfig> {\n\tconst definition = router.definition;\n\n\tlet workflow: Workflow<TConfig> = loadOrCreate(definition, initialConfig, options);\n\tlet isDispatching = false;\n\tlet error: PipelineError<TConfig> | null = null;\n\tlet snapshot: WorkflowStoreSnapshot<TConfig> = {\n\t\tworkflow,\n\t\tisLoading: false,\n\t\tisDispatching,\n\t\terror,\n\t};\n\tconst listeners = new Set<() => void>();\n\n\tfunction notify() {\n\t\tsnapshot = { workflow, isLoading: false, isDispatching, error };\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t}\n\n\tconst dispatch = async <C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\tpayload: CommandPayload<TConfig, C>,\n\t): Promise<DispatchResult<TConfig>> => {\n\t\tisDispatching = true;\n\t\tnotify();\n\n\t\tconst result = await router.dispatch(workflow, { type: command, payload });\n\n\t\tif (result.ok) {\n\t\t\tworkflow = result.workflow;\n\t\t\terror = null;\n\t\t} else {\n\t\t\terror = result.error;\n\t\t}\n\t\tisDispatching = false;\n\t\tnotify();\n\n\t\tif (result.ok && options?.persist) {\n\t\t\tconst { key, storage } = options.persist;\n\t\t\tconst snap = definition.serialize(workflow);\n\t\t\tstorage.setItem(key, JSON.stringify(snap));\n\t\t}\n\n\t\treturn result;\n\t};\n\n\treturn {\n\t\tgetWorkflow: () => workflow,\n\t\tgetSnapshot: () => snapshot,\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tdispatch,\n\t\tsetWorkflow: (newWorkflow) => {\n\t\t\tworkflow = newWorkflow;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t},\n\t\tcleanup() {},\n\t};\n}\n\nfunction loadOrCreate<TConfig extends WorkflowConfig, S extends StateNames<TConfig>>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\tinitialConfig: { state: S; data: StateData<TConfig, S>; id?: string },\n\toptions?: WorkflowStoreOptions<TConfig>,\n): Workflow<TConfig> {\n\tif (options?.persist) {\n\t\tconst { key, storage, migrations } = options.persist;\n\t\ttry {\n\t\t\tconst stored = storage.getItem(key);\n\t\t\tif (stored) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: JSON.parse returns unknown structure from storage\n\t\t\t\tlet parsed: any = JSON.parse(stored);\n\t\t\t\tif (migrations) {\n\t\t\t\t\tconst migrated = migrate(migrations, parsed);\n\t\t\t\t\tif (migrated.ok) {\n\t\t\t\t\t\tparsed = migrated.snapshot;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn createFresh(definition, initialConfig);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst restored = definition.deserialize(parsed);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\treturn restored.workflow;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Invalid JSON or deserialize failed — fall through to create fresh\n\t\t}\n\t}\n\n\treturn createFresh(definition, initialConfig);\n}\n\nfunction createFresh<TConfig extends WorkflowConfig, S extends StateNames<TConfig>>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\tinitialConfig: { state: S; data: StateData<TConfig, S>; id?: string },\n): Workflow<TConfig> {\n\treturn definition.createWorkflow(initialConfig.id ?? crypto.randomUUID(), {\n\t\tinitialState: initialConfig.state,\n\t\tdata: initialConfig.data,\n\t});\n}\n"],"mappings":"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","names":["import_react"]}
|
package/dist/index.js
CHANGED
|
@@ -8,13 +8,13 @@ function createWorkflowClient(transport) {
|
|
|
8
8
|
if (existing) {
|
|
9
9
|
return existing;
|
|
10
10
|
}
|
|
11
|
-
const store = createRemoteStore(transport, definition, id);
|
|
11
|
+
const store = createRemoteStore(transport, definition, id, () => cache.delete(cacheKey));
|
|
12
12
|
cache.set(cacheKey, store);
|
|
13
13
|
return store;
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
function createRemoteStore(transport, definition, id) {
|
|
17
|
+
function createRemoteStore(transport, definition, id, onDispose) {
|
|
18
18
|
let workflow = null;
|
|
19
19
|
let version = 0;
|
|
20
20
|
let isLoading = true;
|
|
@@ -142,6 +142,7 @@ function createRemoteStore(transport, definition, id) {
|
|
|
142
142
|
cleanup() {
|
|
143
143
|
disposed = true;
|
|
144
144
|
subscription.unsubscribe();
|
|
145
|
+
onDispose();
|
|
145
146
|
}
|
|
146
147
|
};
|
|
147
148
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/context.ts","../src/use-workflow.ts","../src/store.ts"],"sourcesContent":["import type {\n\tCommandNames,\n\tCommandPayload,\n\tDispatchResult,\n\tPipelineError,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowDefinition,\n} from \"@rytejs/core\";\nimport type { BroadcastMessage, Transport } from \"./transport.js\";\nimport type { WorkflowStore, WorkflowStoreSnapshot } from \"./types.js\";\n\nexport function createWorkflowClient(transport: Transport) {\n\t// biome-ignore lint/suspicious/noExplicitAny: cache stores keyed by string, values are type-erased WorkflowStore instances\n\tconst cache = new Map<string, WorkflowStore<any>>();\n\n\treturn {\n\t\tconnect<TConfig extends WorkflowConfig>(\n\t\t\tdefinition: WorkflowDefinition<TConfig>,\n\t\t\tid: string,\n\t\t): WorkflowStore<TConfig> {\n\t\t\tconst cacheKey = `${definition.name}:${id}`;\n\t\t\tconst existing = cache.get(cacheKey);\n\t\t\tif (existing) {\n\t\t\t\treturn existing as WorkflowStore<TConfig>;\n\t\t\t}\n\n\t\t\tconst store = createRemoteStore(transport, definition, id);\n\t\t\tcache.set(cacheKey, store);\n\t\t\treturn store;\n\t\t},\n\t};\n}\n\nfunction createRemoteStore<TConfig extends WorkflowConfig>(\n\ttransport: Transport,\n\tdefinition: WorkflowDefinition<TConfig>,\n\tid: string,\n): WorkflowStore<TConfig> {\n\tlet workflow: Workflow<TConfig> | null = null;\n\tlet version = 0;\n\tlet isLoading = true;\n\tlet isDispatching = false;\n\tlet error: PipelineError<TConfig> | null = null;\n\tlet disposed = false;\n\n\tconst listeners = new Set<() => void>();\n\n\tlet snapshot: WorkflowStoreSnapshot<TConfig> = {\n\t\tworkflow,\n\t\tisLoading,\n\t\tisDispatching,\n\t\terror,\n\t};\n\n\tfunction notify() {\n\t\tif (disposed) return;\n\t\tsnapshot = { workflow, isLoading, isDispatching, error };\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t}\n\n\t// Eagerly load\n\ttransport\n\t\t.load(id)\n\t\t.then((result) => {\n\t\t\tif (disposed) return;\n\t\t\tif (result !== null) {\n\t\t\t\tconst restored = definition.deserialize(result.snapshot);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\tworkflow = restored.workflow;\n\t\t\t\t\tversion = result.version;\n\t\t\t\t}\n\t\t\t}\n\t\t\tisLoading = false;\n\t\t\tnotify();\n\t\t})\n\t\t.catch((err: unknown) => {\n\t\t\tif (disposed) return;\n\t\t\terror = {\n\t\t\t\tcategory: \"unexpected\",\n\t\t\t\terror: err,\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: TransportError mapped to PipelineError shape for interface conformance\n\t\t\t} as any;\n\t\t\tisLoading = false;\n\t\t\tnotify();\n\t\t});\n\n\t// Subscribe to live broadcasts\n\tconst subscription = transport.subscribe(id, (message: BroadcastMessage) => {\n\t\tif (disposed) return;\n\t\tconst restored = definition.deserialize(message.snapshot);\n\t\tif (restored.ok) {\n\t\t\tworkflow = restored.workflow;\n\t\t\tversion = message.version;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t}\n\t});\n\n\tconst dispatch = async <C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\tpayload: CommandPayload<TConfig, C>,\n\t): Promise<DispatchResult<TConfig>> => {\n\t\tif (isLoading) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\terror: new Error(\"Cannot dispatch while loading\"),\n\t\t\t\t\tmessage: \"Cannot dispatch while loading\",\n\t\t\t\t},\n\t\t\t} as DispatchResult<TConfig>;\n\t\t}\n\n\t\tisDispatching = true;\n\t\tnotify();\n\n\t\ttry {\n\t\t\tconst result = await transport.dispatch(id, { type: command as string, payload }, version);\n\n\t\t\tif (result.ok) {\n\t\t\t\tconst restored = definition.deserialize(result.snapshot);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\tworkflow = restored.workflow;\n\t\t\t\t\tversion = result.version;\n\t\t\t\t\terror = null;\n\t\t\t\t\tisDispatching = false;\n\t\t\t\t\tnotify();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tworkflow: restored.workflow,\n\t\t\t\t\t\tevents: result.events,\n\t\t\t\t\t} as DispatchResult<TConfig>;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Error path\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: TransportError mapped to PipelineError shape\n\t\t\terror = (result.ok ? null : result.error) as any;\n\t\t\tisDispatching = false;\n\t\t\tnotify();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: error ?? {\n\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\terror: new Error(\"Transport error\"),\n\t\t\t\t\tmessage: \"Transport error\",\n\t\t\t\t},\n\t\t\t} as DispatchResult<TConfig>;\n\t\t} catch (err: unknown) {\n\t\t\terror = {\n\t\t\t\tcategory: \"unexpected\",\n\t\t\t\terror: err,\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: network error mapped to PipelineError shape\n\t\t\t} as any;\n\t\t\tisDispatching = false;\n\t\t\tnotify();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: error is always assigned in the catch block above\n\t\t\t\terror: error!,\n\t\t\t} as DispatchResult<TConfig>;\n\t\t}\n\t};\n\n\treturn {\n\t\tgetWorkflow: () => workflow,\n\t\tgetSnapshot: () => snapshot,\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tdispatch,\n\t\tsetWorkflow: (newWorkflow) => {\n\t\t\tworkflow = newWorkflow;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t},\n\t\tcleanup() {\n\t\t\tdisposed = true;\n\t\t\tsubscription.unsubscribe();\n\t\t},\n\t};\n}\n","import type { Workflow, WorkflowConfig, WorkflowDefinition } from \"@rytejs/core\";\nimport type { ReactNode } from \"react\";\nimport { createContext, createElement, useContext } from \"react\";\nimport type { UseWorkflowReturn, WorkflowStore } from \"./types.js\";\nimport { useWorkflow } from \"./use-workflow.js\";\n\nexport function createWorkflowContext<TConfig extends WorkflowConfig>(\n\t_definition: WorkflowDefinition<TConfig>,\n): {\n\tProvider: (props: { store: WorkflowStore<TConfig>; children?: ReactNode }) => ReactNode;\n\tuseWorkflow: {\n\t\t(): UseWorkflowReturn<TConfig>;\n\t\t<R>(selector: (workflow: Workflow<TConfig>) => R, equalityFn?: (a: R, b: R) => boolean): R;\n\t};\n} {\n\tconst StoreContext = createContext<WorkflowStore<TConfig> | null>(null);\n\n\tfunction Provider({\n\t\tstore,\n\t\tchildren,\n\t}: {\n\t\tstore: WorkflowStore<TConfig>;\n\t\tchildren?: ReactNode;\n\t}): ReactNode {\n\t\treturn createElement(StoreContext.Provider, { value: store }, children);\n\t}\n\n\tfunction useWorkflowFromContext(): UseWorkflowReturn<TConfig>;\n\tfunction useWorkflowFromContext<R>(\n\t\tselector: (workflow: Workflow<TConfig>) => R,\n\t\tequalityFn?: (a: R, b: R) => boolean,\n\t): R;\n\tfunction useWorkflowFromContext<R>(\n\t\tselector?: (workflow: Workflow<TConfig>) => R,\n\t\tequalityFn?: (a: R, b: R) => boolean,\n\t): UseWorkflowReturn<TConfig> | R {\n\t\tconst store = useContext(StoreContext);\n\t\tif (!store) {\n\t\t\tthrow new Error(\n\t\t\t\t\"useWorkflow must be used within a WorkflowProvider. \" +\n\t\t\t\t\t\"Wrap your component tree with <Provider store={...}>.\",\n\t\t\t);\n\t\t}\n\t\tif (selector) {\n\t\t\t// biome-ignore lint/correctness/useHookAtTopLevel: selector presence is stable per render — callers must not change between selector and no-selector mode\n\t\t\treturn useWorkflow(store, selector, equalityFn);\n\t\t}\n\t\t// biome-ignore lint/correctness/useHookAtTopLevel: called on the non-selector path; mutually exclusive with the branch above but stable per component lifetime\n\t\treturn useWorkflow(store);\n\t}\n\n\treturn { Provider, useWorkflow: useWorkflowFromContext };\n}\n","import type { Workflow, WorkflowConfig } from \"@rytejs/core\";\nimport { useCallback, useRef, useSyncExternalStore } from \"react\";\nimport type { UseWorkflowReturn, WorkflowStore, WorkflowStoreSnapshot } from \"./types.js\";\n\nfunction createReturn<TConfig extends WorkflowConfig>(\n\tsnapshot: WorkflowStoreSnapshot<TConfig>,\n\tdispatch: WorkflowStore<TConfig>[\"dispatch\"],\n): UseWorkflowReturn<TConfig> {\n\tconst wf = snapshot.workflow;\n\treturn {\n\t\tworkflow: wf,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: state/data are undefined when workflow is null (loading) — consumers check isLoading first\n\t\tstate: wf?.state as any,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: see above\n\t\tdata: wf?.data as any,\n\t\tisLoading: snapshot.isLoading,\n\t\tisDispatching: snapshot.isDispatching,\n\t\terror: snapshot.error,\n\t\tdispatch,\n\t\tmatch(\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t\tmatchers: Record<string, any>,\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t\tfallback?: (workflow: Workflow<TConfig> | null) => any,\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t): any {\n\t\t\tif (!wf) {\n\t\t\t\tif (fallback) return fallback(wf);\n\t\t\t\tthrow new Error(\"Cannot match on a loading workflow — check isLoading first\");\n\t\t\t}\n\t\t\tconst state = wf.state as string;\n\t\t\tconst matcher = matchers[state];\n\t\t\tif (matcher) {\n\t\t\t\treturn matcher(wf.data, wf);\n\t\t\t}\n\t\t\tif (fallback) {\n\t\t\t\treturn fallback(wf);\n\t\t\t}\n\t\t\tthrow new Error(`No match for state \"${state}\" and no fallback provided`);\n\t\t},\n\t} as UseWorkflowReturn<TConfig>;\n}\n\nexport function useWorkflow<TConfig extends WorkflowConfig>(\n\tstore: WorkflowStore<TConfig>,\n): UseWorkflowReturn<TConfig>;\nexport function useWorkflow<TConfig extends WorkflowConfig, R>(\n\tstore: WorkflowStore<TConfig>,\n\tselector: (workflow: Workflow<TConfig>) => R,\n\tequalityFn?: (a: R, b: R) => boolean,\n): R;\nexport function useWorkflow<TConfig extends WorkflowConfig, R>(\n\tstore: WorkflowStore<TConfig>,\n\tselector?: (workflow: Workflow<TConfig>) => R,\n\tequalityFn?: (a: R, b: R) => boolean,\n): UseWorkflowReturn<TConfig> | R {\n\t// Refs for selector caching — always allocated to maintain hook call order\n\tconst selectorRef = useRef(selector);\n\tconst equalityFnRef = useRef(equalityFn);\n\tconst cachedRef = useRef<R | undefined>(undefined);\n\tconst hasCachedRef = useRef(false);\n\tselectorRef.current = selector;\n\tequalityFnRef.current = equalityFn;\n\n\tconst selectorSnapshot = useCallback(() => {\n\t\tconst wf = store.getWorkflow();\n\t\tif (!wf) {\n\t\t\t// Workflow is loading — return cached value if available\n\t\t\treturn cachedRef.current;\n\t\t}\n\t\t// biome-ignore lint/style/noNonNullAssertion: selectorSnapshot is only used when selector is defined (checked at call site)\n\t\tconst next = selectorRef.current!(wf);\n\t\tconst eq = equalityFnRef.current ?? Object.is;\n\t\tif (hasCachedRef.current && eq(cachedRef.current as R, next)) {\n\t\t\treturn cachedRef.current;\n\t\t}\n\t\tcachedRef.current = next;\n\t\thasCachedRef.current = true;\n\t\treturn next;\n\t}, [store]);\n\n\t// biome-ignore lint/suspicious/noExplicitAny: return type varies by overload; TS can't narrow union of getSnapshot functions\n\tconst getSnapshot: () => any = selector ? selectorSnapshot : store.getSnapshot;\n\n\tconst result: unknown = useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n\n\tif (!selector) {\n\t\treturn createReturn(result as WorkflowStoreSnapshot<TConfig>, store.dispatch);\n\t}\n\treturn result as R;\n}\n","import type {\n\tCommandNames,\n\tCommandPayload,\n\tDispatchResult,\n\tPipelineError,\n\tStateData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowDefinition,\n} from \"@rytejs/core\";\nimport { migrate, type WorkflowRouter } from \"@rytejs/core\";\nimport type { WorkflowStore, WorkflowStoreOptions, WorkflowStoreSnapshot } from \"./types.js\";\n\nexport function createWorkflowStore<\n\tTConfig extends WorkflowConfig,\n\tTDeps,\n\tS extends StateNames<TConfig>,\n>(\n\trouter: WorkflowRouter<TConfig, TDeps>,\n\tinitialConfig: {\n\t\tstate: S;\n\t\tdata: StateData<TConfig, S>;\n\t\tid?: string;\n\t},\n\toptions?: WorkflowStoreOptions<TConfig>,\n): WorkflowStore<TConfig> {\n\tconst definition = router.definition;\n\n\tlet workflow: Workflow<TConfig> = loadOrCreate(definition, initialConfig, options);\n\tlet isDispatching = false;\n\tlet error: PipelineError<TConfig> | null = null;\n\tlet snapshot: WorkflowStoreSnapshot<TConfig> = {\n\t\tworkflow,\n\t\tisLoading: false,\n\t\tisDispatching,\n\t\terror,\n\t};\n\tconst listeners = new Set<() => void>();\n\n\tfunction notify() {\n\t\tsnapshot = { workflow, isLoading: false, isDispatching, error };\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t}\n\n\tconst dispatch = async <C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\tpayload: CommandPayload<TConfig, C>,\n\t): Promise<DispatchResult<TConfig>> => {\n\t\tisDispatching = true;\n\t\tnotify();\n\n\t\tconst result = await router.dispatch(workflow, { type: command, payload });\n\n\t\tif (result.ok) {\n\t\t\tworkflow = result.workflow;\n\t\t\terror = null;\n\t\t} else {\n\t\t\terror = result.error;\n\t\t}\n\t\tisDispatching = false;\n\t\tnotify();\n\n\t\tif (result.ok && options?.persist) {\n\t\t\tconst { key, storage } = options.persist;\n\t\t\tconst snap = definition.serialize(workflow);\n\t\t\tstorage.setItem(key, JSON.stringify(snap));\n\t\t}\n\n\t\treturn result;\n\t};\n\n\treturn {\n\t\tgetWorkflow: () => workflow,\n\t\tgetSnapshot: () => snapshot,\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tdispatch,\n\t\tsetWorkflow: (newWorkflow) => {\n\t\t\tworkflow = newWorkflow;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t},\n\t\tcleanup() {},\n\t};\n}\n\nfunction loadOrCreate<TConfig extends WorkflowConfig, S extends StateNames<TConfig>>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\tinitialConfig: { state: S; data: StateData<TConfig, S>; id?: string },\n\toptions?: WorkflowStoreOptions<TConfig>,\n): Workflow<TConfig> {\n\tif (options?.persist) {\n\t\tconst { key, storage, migrations } = options.persist;\n\t\ttry {\n\t\t\tconst stored = storage.getItem(key);\n\t\t\tif (stored) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: JSON.parse returns unknown structure from storage\n\t\t\t\tlet parsed: any = JSON.parse(stored);\n\t\t\t\tif (migrations) {\n\t\t\t\t\tconst migrated = migrate(migrations, parsed);\n\t\t\t\t\tif (migrated.ok) {\n\t\t\t\t\t\tparsed = migrated.snapshot;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn createFresh(definition, initialConfig);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst restored = definition.deserialize(parsed);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\treturn restored.workflow;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Invalid JSON or deserialize failed — fall through to create fresh\n\t\t}\n\t}\n\n\treturn createFresh(definition, initialConfig);\n}\n\nfunction createFresh<TConfig extends WorkflowConfig, S extends StateNames<TConfig>>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\tinitialConfig: { state: S; data: StateData<TConfig, S>; id?: string },\n): Workflow<TConfig> {\n\treturn definition.createWorkflow(initialConfig.id ?? crypto.randomUUID(), {\n\t\tinitialState: initialConfig.state,\n\t\tdata: initialConfig.data,\n\t});\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/context.ts","../src/use-workflow.ts","../src/store.ts"],"sourcesContent":["import type {\n\tCommandNames,\n\tCommandPayload,\n\tDispatchResult,\n\tPipelineError,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowDefinition,\n} from \"@rytejs/core\";\nimport type { BroadcastMessage, Transport } from \"./transport.js\";\nimport type { WorkflowStore, WorkflowStoreSnapshot } from \"./types.js\";\n\nexport function createWorkflowClient(transport: Transport) {\n\t// biome-ignore lint/suspicious/noExplicitAny: cache stores keyed by string, values are type-erased WorkflowStore instances\n\tconst cache = new Map<string, WorkflowStore<any>>();\n\n\treturn {\n\t\tconnect<TConfig extends WorkflowConfig>(\n\t\t\tdefinition: WorkflowDefinition<TConfig>,\n\t\t\tid: string,\n\t\t): WorkflowStore<TConfig> {\n\t\t\tconst cacheKey = `${definition.name}:${id}`;\n\t\t\tconst existing = cache.get(cacheKey);\n\t\t\tif (existing) {\n\t\t\t\treturn existing as WorkflowStore<TConfig>;\n\t\t\t}\n\n\t\t\tconst store = createRemoteStore(transport, definition, id, () => cache.delete(cacheKey));\n\t\t\tcache.set(cacheKey, store);\n\t\t\treturn store;\n\t\t},\n\t};\n}\n\nfunction createRemoteStore<TConfig extends WorkflowConfig>(\n\ttransport: Transport,\n\tdefinition: WorkflowDefinition<TConfig>,\n\tid: string,\n\tonDispose: () => void,\n): WorkflowStore<TConfig> {\n\tlet workflow: Workflow<TConfig> | null = null;\n\tlet version = 0;\n\tlet isLoading = true;\n\tlet isDispatching = false;\n\tlet error: PipelineError<TConfig> | null = null;\n\tlet disposed = false;\n\n\tconst listeners = new Set<() => void>();\n\n\tlet snapshot: WorkflowStoreSnapshot<TConfig> = {\n\t\tworkflow,\n\t\tisLoading,\n\t\tisDispatching,\n\t\terror,\n\t};\n\n\tfunction notify() {\n\t\tif (disposed) return;\n\t\tsnapshot = { workflow, isLoading, isDispatching, error };\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t}\n\n\t// Eagerly load\n\ttransport\n\t\t.load(id)\n\t\t.then((result) => {\n\t\t\tif (disposed) return;\n\t\t\tif (result !== null) {\n\t\t\t\tconst restored = definition.deserialize(result.snapshot);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\tworkflow = restored.workflow;\n\t\t\t\t\tversion = result.version;\n\t\t\t\t}\n\t\t\t}\n\t\t\tisLoading = false;\n\t\t\tnotify();\n\t\t})\n\t\t.catch((err: unknown) => {\n\t\t\tif (disposed) return;\n\t\t\terror = {\n\t\t\t\tcategory: \"unexpected\",\n\t\t\t\terror: err,\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: TransportError mapped to PipelineError shape for interface conformance\n\t\t\t} as any;\n\t\t\tisLoading = false;\n\t\t\tnotify();\n\t\t});\n\n\t// Subscribe to live broadcasts\n\tconst subscription = transport.subscribe(id, (message: BroadcastMessage) => {\n\t\tif (disposed) return;\n\t\tconst restored = definition.deserialize(message.snapshot);\n\t\tif (restored.ok) {\n\t\t\tworkflow = restored.workflow;\n\t\t\tversion = message.version;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t}\n\t});\n\n\tconst dispatch = async <C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\tpayload: CommandPayload<TConfig, C>,\n\t): Promise<DispatchResult<TConfig>> => {\n\t\tif (isLoading) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: {\n\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\terror: new Error(\"Cannot dispatch while loading\"),\n\t\t\t\t\tmessage: \"Cannot dispatch while loading\",\n\t\t\t\t},\n\t\t\t} as DispatchResult<TConfig>;\n\t\t}\n\n\t\tisDispatching = true;\n\t\tnotify();\n\n\t\ttry {\n\t\t\tconst result = await transport.dispatch(id, { type: command as string, payload }, version);\n\n\t\t\tif (result.ok) {\n\t\t\t\tconst restored = definition.deserialize(result.snapshot);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\tworkflow = restored.workflow;\n\t\t\t\t\tversion = result.version;\n\t\t\t\t\terror = null;\n\t\t\t\t\tisDispatching = false;\n\t\t\t\t\tnotify();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tworkflow: restored.workflow,\n\t\t\t\t\t\tevents: result.events,\n\t\t\t\t\t} as DispatchResult<TConfig>;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Error path\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: TransportError mapped to PipelineError shape\n\t\t\terror = (result.ok ? null : result.error) as any;\n\t\t\tisDispatching = false;\n\t\t\tnotify();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: error ?? {\n\t\t\t\t\tcategory: \"unexpected\",\n\t\t\t\t\terror: new Error(\"Transport error\"),\n\t\t\t\t\tmessage: \"Transport error\",\n\t\t\t\t},\n\t\t\t} as DispatchResult<TConfig>;\n\t\t} catch (err: unknown) {\n\t\t\terror = {\n\t\t\t\tcategory: \"unexpected\",\n\t\t\t\terror: err,\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: network error mapped to PipelineError shape\n\t\t\t} as any;\n\t\t\tisDispatching = false;\n\t\t\tnotify();\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: error is always assigned in the catch block above\n\t\t\t\terror: error!,\n\t\t\t} as DispatchResult<TConfig>;\n\t\t}\n\t};\n\n\treturn {\n\t\tgetWorkflow: () => workflow,\n\t\tgetSnapshot: () => snapshot,\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tdispatch,\n\t\tsetWorkflow: (newWorkflow) => {\n\t\t\tworkflow = newWorkflow;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t},\n\t\tcleanup() {\n\t\t\tdisposed = true;\n\t\t\tsubscription.unsubscribe();\n\t\t\tonDispose();\n\t\t},\n\t};\n}\n","import type { Workflow, WorkflowConfig, WorkflowDefinition } from \"@rytejs/core\";\nimport type { ReactNode } from \"react\";\nimport { createContext, createElement, useContext } from \"react\";\nimport type { UseWorkflowReturn, WorkflowStore } from \"./types.js\";\nimport { useWorkflow } from \"./use-workflow.js\";\n\nexport function createWorkflowContext<TConfig extends WorkflowConfig>(\n\t_definition: WorkflowDefinition<TConfig>,\n): {\n\tProvider: (props: { store: WorkflowStore<TConfig>; children?: ReactNode }) => ReactNode;\n\tuseWorkflow: {\n\t\t(): UseWorkflowReturn<TConfig>;\n\t\t<R>(selector: (workflow: Workflow<TConfig>) => R, equalityFn?: (a: R, b: R) => boolean): R;\n\t};\n} {\n\tconst StoreContext = createContext<WorkflowStore<TConfig> | null>(null);\n\n\tfunction Provider({\n\t\tstore,\n\t\tchildren,\n\t}: {\n\t\tstore: WorkflowStore<TConfig>;\n\t\tchildren?: ReactNode;\n\t}): ReactNode {\n\t\treturn createElement(StoreContext.Provider, { value: store }, children);\n\t}\n\n\tfunction useWorkflowFromContext(): UseWorkflowReturn<TConfig>;\n\tfunction useWorkflowFromContext<R>(\n\t\tselector: (workflow: Workflow<TConfig>) => R,\n\t\tequalityFn?: (a: R, b: R) => boolean,\n\t): R;\n\tfunction useWorkflowFromContext<R>(\n\t\tselector?: (workflow: Workflow<TConfig>) => R,\n\t\tequalityFn?: (a: R, b: R) => boolean,\n\t): UseWorkflowReturn<TConfig> | R {\n\t\tconst store = useContext(StoreContext);\n\t\tif (!store) {\n\t\t\tthrow new Error(\n\t\t\t\t\"useWorkflow must be used within a WorkflowProvider. \" +\n\t\t\t\t\t\"Wrap your component tree with <Provider store={...}>.\",\n\t\t\t);\n\t\t}\n\t\tif (selector) {\n\t\t\t// biome-ignore lint/correctness/useHookAtTopLevel: selector presence is stable per render — callers must not change between selector and no-selector mode\n\t\t\treturn useWorkflow(store, selector, equalityFn);\n\t\t}\n\t\t// biome-ignore lint/correctness/useHookAtTopLevel: called on the non-selector path; mutually exclusive with the branch above but stable per component lifetime\n\t\treturn useWorkflow(store);\n\t}\n\n\treturn { Provider, useWorkflow: useWorkflowFromContext };\n}\n","import type { Workflow, WorkflowConfig } from \"@rytejs/core\";\nimport { useCallback, useRef, useSyncExternalStore } from \"react\";\nimport type { UseWorkflowReturn, WorkflowStore, WorkflowStoreSnapshot } from \"./types.js\";\n\nfunction createReturn<TConfig extends WorkflowConfig>(\n\tsnapshot: WorkflowStoreSnapshot<TConfig>,\n\tdispatch: WorkflowStore<TConfig>[\"dispatch\"],\n): UseWorkflowReturn<TConfig> {\n\tconst wf = snapshot.workflow;\n\treturn {\n\t\tworkflow: wf,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: state/data are undefined when workflow is null (loading) — consumers check isLoading first\n\t\tstate: wf?.state as any,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: see above\n\t\tdata: wf?.data as any,\n\t\tisLoading: snapshot.isLoading,\n\t\tisDispatching: snapshot.isDispatching,\n\t\terror: snapshot.error,\n\t\tdispatch,\n\t\tmatch(\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t\tmatchers: Record<string, any>,\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t\tfallback?: (workflow: Workflow<TConfig> | null) => any,\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: match overloads handled by UseWorkflowReturn type\n\t\t): any {\n\t\t\tif (!wf) {\n\t\t\t\tif (fallback) return fallback(wf);\n\t\t\t\tthrow new Error(\"Cannot match on a loading workflow — check isLoading first\");\n\t\t\t}\n\t\t\tconst state = wf.state as string;\n\t\t\tconst matcher = matchers[state];\n\t\t\tif (matcher) {\n\t\t\t\treturn matcher(wf.data, wf);\n\t\t\t}\n\t\t\tif (fallback) {\n\t\t\t\treturn fallback(wf);\n\t\t\t}\n\t\t\tthrow new Error(`No match for state \"${state}\" and no fallback provided`);\n\t\t},\n\t} as UseWorkflowReturn<TConfig>;\n}\n\nexport function useWorkflow<TConfig extends WorkflowConfig>(\n\tstore: WorkflowStore<TConfig>,\n): UseWorkflowReturn<TConfig>;\nexport function useWorkflow<TConfig extends WorkflowConfig, R>(\n\tstore: WorkflowStore<TConfig>,\n\tselector: (workflow: Workflow<TConfig>) => R,\n\tequalityFn?: (a: R, b: R) => boolean,\n): R;\nexport function useWorkflow<TConfig extends WorkflowConfig, R>(\n\tstore: WorkflowStore<TConfig>,\n\tselector?: (workflow: Workflow<TConfig>) => R,\n\tequalityFn?: (a: R, b: R) => boolean,\n): UseWorkflowReturn<TConfig> | R {\n\t// Refs for selector caching — always allocated to maintain hook call order\n\tconst selectorRef = useRef(selector);\n\tconst equalityFnRef = useRef(equalityFn);\n\tconst cachedRef = useRef<R | undefined>(undefined);\n\tconst hasCachedRef = useRef(false);\n\tselectorRef.current = selector;\n\tequalityFnRef.current = equalityFn;\n\n\tconst selectorSnapshot = useCallback(() => {\n\t\tconst wf = store.getWorkflow();\n\t\tif (!wf) {\n\t\t\t// Workflow is loading — return cached value if available\n\t\t\treturn cachedRef.current;\n\t\t}\n\t\t// biome-ignore lint/style/noNonNullAssertion: selectorSnapshot is only used when selector is defined (checked at call site)\n\t\tconst next = selectorRef.current!(wf);\n\t\tconst eq = equalityFnRef.current ?? Object.is;\n\t\tif (hasCachedRef.current && eq(cachedRef.current as R, next)) {\n\t\t\treturn cachedRef.current;\n\t\t}\n\t\tcachedRef.current = next;\n\t\thasCachedRef.current = true;\n\t\treturn next;\n\t}, [store]);\n\n\t// biome-ignore lint/suspicious/noExplicitAny: return type varies by overload; TS can't narrow union of getSnapshot functions\n\tconst getSnapshot: () => any = selector ? selectorSnapshot : store.getSnapshot;\n\n\tconst result: unknown = useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n\n\tif (!selector) {\n\t\treturn createReturn(result as WorkflowStoreSnapshot<TConfig>, store.dispatch);\n\t}\n\treturn result as R;\n}\n","import type {\n\tCommandNames,\n\tCommandPayload,\n\tDispatchResult,\n\tPipelineError,\n\tStateData,\n\tStateNames,\n\tWorkflow,\n\tWorkflowConfig,\n\tWorkflowDefinition,\n} from \"@rytejs/core\";\nimport { migrate, type WorkflowRouter } from \"@rytejs/core\";\nimport type { WorkflowStore, WorkflowStoreOptions, WorkflowStoreSnapshot } from \"./types.js\";\n\nexport function createWorkflowStore<\n\tTConfig extends WorkflowConfig,\n\tTDeps,\n\tS extends StateNames<TConfig>,\n>(\n\trouter: WorkflowRouter<TConfig, TDeps>,\n\tinitialConfig: {\n\t\tstate: S;\n\t\tdata: StateData<TConfig, S>;\n\t\tid?: string;\n\t},\n\toptions?: WorkflowStoreOptions<TConfig>,\n): WorkflowStore<TConfig> {\n\tconst definition = router.definition;\n\n\tlet workflow: Workflow<TConfig> = loadOrCreate(definition, initialConfig, options);\n\tlet isDispatching = false;\n\tlet error: PipelineError<TConfig> | null = null;\n\tlet snapshot: WorkflowStoreSnapshot<TConfig> = {\n\t\tworkflow,\n\t\tisLoading: false,\n\t\tisDispatching,\n\t\terror,\n\t};\n\tconst listeners = new Set<() => void>();\n\n\tfunction notify() {\n\t\tsnapshot = { workflow, isLoading: false, isDispatching, error };\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t}\n\n\tconst dispatch = async <C extends CommandNames<TConfig>>(\n\t\tcommand: C,\n\t\tpayload: CommandPayload<TConfig, C>,\n\t): Promise<DispatchResult<TConfig>> => {\n\t\tisDispatching = true;\n\t\tnotify();\n\n\t\tconst result = await router.dispatch(workflow, { type: command, payload });\n\n\t\tif (result.ok) {\n\t\t\tworkflow = result.workflow;\n\t\t\terror = null;\n\t\t} else {\n\t\t\terror = result.error;\n\t\t}\n\t\tisDispatching = false;\n\t\tnotify();\n\n\t\tif (result.ok && options?.persist) {\n\t\t\tconst { key, storage } = options.persist;\n\t\t\tconst snap = definition.serialize(workflow);\n\t\t\tstorage.setItem(key, JSON.stringify(snap));\n\t\t}\n\n\t\treturn result;\n\t};\n\n\treturn {\n\t\tgetWorkflow: () => workflow,\n\t\tgetSnapshot: () => snapshot,\n\t\tsubscribe: (listener) => {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\t\tdispatch,\n\t\tsetWorkflow: (newWorkflow) => {\n\t\t\tworkflow = newWorkflow;\n\t\t\terror = null;\n\t\t\tnotify();\n\t\t},\n\t\tcleanup() {},\n\t};\n}\n\nfunction loadOrCreate<TConfig extends WorkflowConfig, S extends StateNames<TConfig>>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\tinitialConfig: { state: S; data: StateData<TConfig, S>; id?: string },\n\toptions?: WorkflowStoreOptions<TConfig>,\n): Workflow<TConfig> {\n\tif (options?.persist) {\n\t\tconst { key, storage, migrations } = options.persist;\n\t\ttry {\n\t\t\tconst stored = storage.getItem(key);\n\t\t\tif (stored) {\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: JSON.parse returns unknown structure from storage\n\t\t\t\tlet parsed: any = JSON.parse(stored);\n\t\t\t\tif (migrations) {\n\t\t\t\t\tconst migrated = migrate(migrations, parsed);\n\t\t\t\t\tif (migrated.ok) {\n\t\t\t\t\t\tparsed = migrated.snapshot;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn createFresh(definition, initialConfig);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst restored = definition.deserialize(parsed);\n\t\t\t\tif (restored.ok) {\n\t\t\t\t\treturn restored.workflow;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Invalid JSON or deserialize failed — fall through to create fresh\n\t\t}\n\t}\n\n\treturn createFresh(definition, initialConfig);\n}\n\nfunction createFresh<TConfig extends WorkflowConfig, S extends StateNames<TConfig>>(\n\tdefinition: WorkflowDefinition<TConfig>,\n\tinitialConfig: { state: S; data: StateData<TConfig, S>; id?: string },\n): Workflow<TConfig> {\n\treturn definition.createWorkflow(initialConfig.id ?? crypto.randomUUID(), {\n\t\tinitialState: initialConfig.state,\n\t\tdata: initialConfig.data,\n\t});\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rytejs/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "React bindings for @rytejs/core — use workflows as reactive state stores",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
],
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"react": ">=18",
|
|
37
|
-
"@rytejs/core": "^0.
|
|
37
|
+
"@rytejs/core": "^0.8.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@testing-library/jest-dom": "^6.9.1",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"typescript": "^5.9.0",
|
|
49
49
|
"vitest": "^4.0.0",
|
|
50
50
|
"zod": "^4.3.0",
|
|
51
|
-
"@rytejs/core": "0.
|
|
51
|
+
"@rytejs/core": "0.8.0"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=20"
|