@@ -140,6 +140,10 @@ export interface IDocLayoutExecutor {
140140 readonly type : DocLayoutExecutorType ;
141141 initialize ( ) : Promise < void > ;
142142 recover ( ) : Promise < void > ;
143+ /**
144+ * Capture the request synchronously before returning. The source document model remains mutable
145+ * while the returned promise tracks remote session creation.
146+ */
143147 createSession ( request : IDocLayoutCreateSessionRequest ) : Promise < void > ;
144148 startLayout ( request : IDocLayoutStartRequest ) : Promise < IDocLayoutStartResult > ;
145149 stepLayout ( request : IDocLayoutStepRequest ) : Promise < IDocLayoutStepResult > ;
@@ -210,6 +214,7 @@ export interface IDocLayoutStartOptions {
210214export class DocLayoutExecutorService extends Disposable {
211215 private static readonly _performanceSampleLimit = 2048 ;
212216 private _executor : Nullable < IDocLayoutExecutor > = null ;
217+ private _executorReady : Promise < void > | null = null ;
213218 private _recoveryFailure : { diagnostic : string ; unitId : string } | null = null ;
214219 private _sessionEpoch = 0 ;
215220 private readonly _sessions = new Map < string , IDocLayoutManagedSession > ( ) ;
@@ -278,7 +283,9 @@ export class DocLayoutExecutorService extends Disposable {
278283 diagnostic : null ,
279284 recoveryUnitId : null ,
280285 } ) ;
281- executor . initialize ( ) . then ( ( ) => {
286+ const executorReady = executor . initialize ( ) ;
287+ this . _executorReady = executorReady ;
288+ executorReady . then ( ( ) => {
282289 if ( this . _executor === executor ) {
283290 this . _executorStatus$ . next ( {
284291 state : DocLayoutExecutorState . ACTIVE ,
@@ -292,6 +299,7 @@ export class DocLayoutExecutorService extends Disposable {
292299 return ;
293300 }
294301 this . _executor = null ;
302+ this . _executorReady = null ;
295303 this . _disposeManagedSessions ( ) ;
296304 this . _sessions . clear ( ) ;
297305 const diagnostic = error instanceof Error ? error . message : String ( error ) ;
@@ -310,6 +318,7 @@ export class DocLayoutExecutorService extends Disposable {
310318 return toDisposable ( ( ) => {
311319 if ( this . _executor === executor ) {
312320 this . _executor = null ;
321+ this . _executorReady = null ;
313322 this . _disposeManagedSessions ( ) ;
314323 this . _sessions . clear ( ) ;
315324 this . _executorStatus$ . next ( {
@@ -364,10 +373,13 @@ export class DocLayoutExecutorService extends Disposable {
364373 this . _hydrationSamples . clear ( ) ;
365374
366375 try {
367- await executor . recover ( ) ;
376+ const executorReady = executor . recover ( ) ;
377+ this . _executorReady = executorReady ;
378+ await executorReady ;
368379 } catch ( error ) {
369380 const recoveryDiagnostic = error instanceof Error ? error . message : String ( error ) ;
370381 this . _executor = null ;
382+ this . _executorReady = null ;
371383 this . _recoveryFailure = { diagnostic : recoveryDiagnostic , unitId } ;
372384 this . _executorStatus$ . next ( {
373385 state : DocLayoutExecutorState . RECOVERING ,
@@ -468,6 +480,7 @@ export class DocLayoutExecutorService extends Disposable {
468480 }
469481 this . _sessions . clear ( ) ;
470482 this . _executor = null ;
483+ this . _executorReady = null ;
471484 this . _recoveryFailure = null ;
472485 this . _executorStatus$ . complete ( ) ;
473486 super . dispose ( ) ;
@@ -606,16 +619,7 @@ export class DocLayoutExecutorService extends Disposable {
606619 disposed : false ,
607620 cancelPendingCreateTask : null ,
608621 } ;
609- const request : IDocLayoutCreateSessionRequest = {
610- unitId,
611- sessionEpoch : session . sessionEpoch ,
612- snapshot : dataModel . getSnapshot ( ) ,
613- modelRevision,
614- locale : this . _localeService . getCurrentLocale ( ) ,
615- localeData : this . _localeService . getLocales ( ) ,
616- direction : this . _localeService . getDirection ( ) ,
617- } ;
618- const createTask = this . _createSessionOnNextMacroTask ( executor , session , request ) ;
622+ const createTask = this . _createSessionOnNextMacroTask ( executor , session , dataModel ) ;
619623 session . queue = createTask ;
620624 this . _sessions . set ( unitId , session ) ;
621625 try {
@@ -685,20 +689,53 @@ export class DocLayoutExecutorService extends Disposable {
685689 private _createSessionOnNextMacroTask (
686690 executor : IDocLayoutExecutor ,
687691 session : IDocLayoutManagedSession ,
688- request : IDocLayoutCreateSessionRequest
692+ dataModel : DocumentDataModel
689693 ) : Promise < void > {
690694 return new Promise < void > ( ( resolve , reject ) => {
691695 const cancelTask = requestImmediateMacroTask ( ( ) => {
692696 session . cancelPendingCreateTask = null ;
697+ const unitId = dataModel . getUnitId ( ) ;
693698 if (
694699 session . disposed ||
695700 this . _executor !== executor ||
696- this . _sessions . get ( request . unitId ) !== session
701+ this . _sessions . get ( unitId ) !== session
697702 ) {
698703 resolve ( ) ;
699704 return ;
700705 }
701- executor . createSession ( request ) . then ( resolve , reject ) ;
706+
707+ const executorReady = this . _executorReady ;
708+ if ( executorReady == null ) {
709+ resolve ( ) ;
710+ return ;
711+ }
712+ executorReady . then ( ( ) => {
713+ if (
714+ session . disposed ||
715+ this . _executor !== executor ||
716+ this . _sessions . get ( unitId ) !== session ||
717+ this . _getEligibleModel ( unitId ) !== dataModel
718+ ) {
719+ resolve ( ) ;
720+ return ;
721+ }
722+
723+ // Mutations committed before the deferred transfer are already present in the
724+ // live model snapshot. Fold them into the baseline instead of replaying them.
725+ session . sourceMutationRevision = dataModel . getMutationRevision ( ) ;
726+ session . workerRevision = session . modelRevision ;
727+ session . pendingMutations . length = 0 ;
728+ const request : IDocLayoutCreateSessionRequest = {
729+ unitId,
730+ sessionEpoch : session . sessionEpoch ,
731+ snapshot : dataModel . getSnapshot ( ) ,
732+ modelRevision : session . modelRevision ,
733+ locale : this . _localeService . getCurrentLocale ( ) ,
734+ localeData : this . _localeService . getLocales ( ) ,
735+ direction : this . _localeService . getDirection ( ) ,
736+ } ;
737+ executor . createSession ( request ) . then ( resolve , reject ) ;
738+ } , reject ) ;
702739 } ) ;
703740 session . cancelPendingCreateTask = ( ) => {
704741 cancelTask ( ) ;
0 commit comments