@@ -43,6 +43,9 @@ type ChildEntry =
4343type ChildSelector = string | ChildDescriptor
4444type ChildKey = string | symbol
4545
46+ /** @internal */
47+ export const activeSnapshotObserver : unique symbol = Symbol . for ( "effect/Machine/activeSnapshotObserver" )
48+
4649interface ChildRegistrySnapshot {
4750 readonly closed : boolean
4851 readonly revision : number
@@ -183,6 +186,9 @@ export interface ProcessSpawn {
183186 readonly onOutcome ?: (
184187 outcome : RuntimeOutcome < ChildState , ChildError , ChildOutput >
185188 ) => Effect . Effect < void >
189+ readonly [ activeSnapshotObserver ] ?: (
190+ snapshot : Extract < RuntimeSnapshot < ChildState , ChildError , ChildOutput > , { readonly status : "active" } >
191+ ) => Effect . Effect < void >
186192 }
187193 ) : Effect . Effect <
188194 MachineRef < ChildState , ChildEvent , ChildError , ChildOutput > ,
@@ -257,6 +263,17 @@ const classifyOutcome = <State, Error, Output>(
257263 }
258264}
259265
266+ const notifyActiveSnapshot = < State , Error , Output > (
267+ onSnapshot : (
268+ snapshot : Extract < RuntimeSnapshot < State , Error , Output > , { readonly status : "active" } >
269+ ) => Effect . Effect < void > ,
270+ snapshot : Extract < RuntimeSnapshot < State , Error , Output > , { readonly status : "active" } >
271+ ) : Effect . Effect < void > =>
272+ Effect . suspend ( ( ) => onSnapshot ( snapshot ) ) . pipe (
273+ Effect . exit ,
274+ Effect . asVoid
275+ )
276+
260277export const watch = < State , Event , Error = never , Output = never > (
261278 ref : MachineRef < State , Event , Error , Output >
262279) : Stream . Stream < RuntimeOutcome < State , Error , Output > > =>
@@ -281,6 +298,9 @@ interface StartInternalOptions {
281298 readonly detached ?: boolean
282299 readonly id ?: string
283300 readonly onOutcome ? : ( outcome : RuntimeOutcome < any , any , any > ) => Effect . Effect < void >
301+ readonly onSnapshot ?: (
302+ snapshot : Extract < RuntimeSnapshot < any , any , any > , { readonly status : "active" } >
303+ ) => Effect . Effect < void >
284304 readonly onReady ?: (
285305 ref : MachineRef < any , any , any , any > ,
286306 requestStop : Effect . Effect < void >
@@ -567,6 +587,9 @@ const startInternal: <
567587 readonly onOutcome ?: (
568588 outcome : RuntimeOutcome < ChildState , ChildError , ChildOutput >
569589 ) => Effect . Effect < void >
590+ readonly [ activeSnapshotObserver ] ?: (
591+ snapshot : Extract < RuntimeSnapshot < ChildState , ChildError , ChildOutput > , { readonly status : "active" } >
592+ ) => Effect . Effect < void >
570593 }
571594 ) : Effect . Effect <
572595 MachineRef < ChildState , ChildEvent , ChildError , ChildOutput > ,
@@ -581,6 +604,9 @@ const startInternal: <
581604 readonly onOutcome ?: (
582605 outcome : RuntimeOutcome < ChildState , ChildError , ChildOutput >
583606 ) => Effect . Effect < void >
607+ readonly [ activeSnapshotObserver ] ?: (
608+ snapshot : Extract < RuntimeSnapshot < ChildState , ChildError , ChildOutput > , { readonly status : "active" } >
609+ ) => Effect . Effect < void >
584610 }
585611 ) : Effect . Effect <
586612 MachineRef < ChildState , ChildEvent , ChildError , ChildOutput > ,
@@ -603,6 +629,9 @@ const startInternal: <
603629 detached : true ,
604630 ...( spawnOptions ?. id === undefined ? undefined : { id : spawnOptions . id } ) ,
605631 ...( spawnOptions ?. onOutcome === undefined ? undefined : { onOutcome : spawnOptions . onOutcome } ) ,
632+ ...( spawnOptions ?. [ activeSnapshotObserver ] === undefined
633+ ? undefined
634+ : { onSnapshot : spawnOptions [ activeSnapshotObserver ] } ) ,
606635 onReady : ( child , requestChildStop ) =>
607636 Effect . sync ( ( ) => {
608637 startedChild = child
@@ -681,12 +710,22 @@ const startInternal: <
681710 state : initial
682711 }
683712 } )
684- const publishSnapshot = (
713+ const publishSnapshot : (
685714 snapshot : VersionedSnapshot < State , Error , Output >
686- ) : Effect . Effect < VersionedSnapshot < State , Error , Output > > =>
687- snapshot . changes === undefined
688- ? Effect . succeed ( snapshot )
689- : PubSub . publish ( snapshot . changes , [ snapshot ] as const ) . pipe ( Effect . as ( snapshot ) )
715+ ) => Effect . Effect < VersionedSnapshot < State , Error , Output > > = options . onSnapshot === undefined
716+ ? ( snapshot ) =>
717+ snapshot . changes === undefined
718+ ? Effect . succeed ( snapshot )
719+ : PubSub . publish ( snapshot . changes , [ snapshot ] as const ) . pipe ( Effect . as ( snapshot ) )
720+ : ( snapshot ) => {
721+ const publish = snapshot . changes === undefined
722+ ? Effect . succeed ( snapshot )
723+ : PubSub . publish ( snapshot . changes , [ snapshot ] as const ) . pipe ( Effect . as ( snapshot ) )
724+ const runtimeSnapshot = snapshot . snapshot
725+ return runtimeSnapshot . status !== "active"
726+ ? publish
727+ : publish . pipe ( Effect . tap ( ( ) => notifyActiveSnapshot ( options . onSnapshot ! , runtimeSnapshot ) ) )
728+ }
690729
691730 const completeChanges = (
692731 snapshot : VersionedSnapshot < State , Error , Output >
@@ -945,6 +984,9 @@ const startInternal: <
945984 if ( options . onReady !== undefined ) {
946985 yield * options . onReady ( ref , requestStop )
947986 }
987+ if ( options . onSnapshot !== undefined ) {
988+ yield * notifyActiveSnapshot ( options . onSnapshot , { status : "active" , state : initial } )
989+ }
948990
949991 const reserveTermination = ( termination : ProcessTermination ) => {
950992 switch ( termination . _tag ) {
0 commit comments