@@ -4,6 +4,7 @@ export interface ProcessingPreviewRequest {
44 featureId : string ;
55 sourceId : string ;
66 params : Record < string , unknown > ;
7+ reuseResult ?: boolean ;
78}
89
910export type ProcessingPreviewState =
@@ -19,6 +20,13 @@ interface QueuedRequest extends ProcessingPreviewRequest {
1920 id : number ;
2021 epoch : number ;
2122 revision : number ;
23+ previewToken : string | null ;
24+ }
25+
26+ let nextPreviewToken = 1 ;
27+
28+ function createPreviewToken ( ) : string {
29+ return `preview-${ Date . now ( ) . toString ( 36 ) } -${ nextPreviewToken ++ } ` ;
2230}
2331
2432function cloneParams ( values : Record < string , unknown > ) : Record < string , unknown > {
@@ -80,11 +88,18 @@ export class ProcessingPreviewController {
8088 private nextId = 1 ;
8189 private epoch = 0 ;
8290 private revision = 0 ;
91+ private currentResult : Pick <
92+ QueuedRequest ,
93+ "previewToken" | "epoch" | "revision"
94+ > | null = null ;
8395 private readonly coordinator : ProcessingPreviewCoordinator ;
8496
8597 constructor (
8698 private readonly onState : ( state : ProcessingPreviewState ) => void ,
87- private readonly runtime : Pick < RuntimeApi , "previewFeature" > ,
99+ private readonly runtime : Pick <
100+ RuntimeApi ,
101+ "previewFeature" | "releasePreviewResult"
102+ > ,
88103 ) {
89104 this . coordinator = coordinatorFor ( runtime as RuntimeApi ) ;
90105 }
@@ -99,11 +114,13 @@ export class ProcessingPreviewController {
99114 }
100115
101116 markDirty ( ) : void {
117+ this . releaseCurrentResult ( ) ;
102118 this . revision += 1 ;
103119 this . coordinator . cancelPending ( this ) ;
104120 }
105121
106122 invalidate ( ) : void {
123+ this . releaseCurrentResult ( ) ;
107124 this . epoch += 1 ;
108125 this . revision += 1 ;
109126 this . coordinator . cancelPending ( this ) ;
@@ -115,6 +132,7 @@ export class ProcessingPreviewController {
115132
116133 request ( request : ProcessingPreviewRequest ) : void {
117134 if ( ! this . enabled ) return ;
135+ this . releaseCurrentResult ( ) ;
118136 if ( this . targetSourceId !== request . sourceId ) {
119137 this . epoch += 1 ;
120138 this . targetSourceId = request . sourceId ;
@@ -126,6 +144,7 @@ export class ProcessingPreviewController {
126144 id : this . nextId ++ ,
127145 epoch : this . epoch ,
128146 revision : this . revision ,
147+ previewToken : request . reuseResult === false ? null : createPreviewToken ( ) ,
129148 } ;
130149 this . onState ( { status : "computing" } ) ;
131150 this . coordinator . submit ( {
@@ -146,15 +165,26 @@ export class ProcessingPreviewController {
146165 request . featureId ,
147166 request . sourceId ,
148167 request . params ,
168+ request . previewToken ,
149169 ) ;
150170 const sameEpoch = this . enabled && request . epoch === this . epoch ;
151- if ( ! sameEpoch ) return ;
171+ if ( ! sameEpoch ) {
172+ this . releaseToken ( request . previewToken ) ;
173+ return ;
174+ }
175+ const current = request . revision === this . revision ;
176+ if ( current && request . previewToken !== null ) {
177+ this . currentResult = request ;
178+ } else {
179+ this . releaseToken ( request . previewToken ) ;
180+ }
152181 this . onState ( {
153182 status : "result" ,
154183 result,
155- current : request . revision === this . revision ,
184+ current,
156185 } ) ;
157186 } catch ( error ) {
187+ this . releaseToken ( request . previewToken ) ;
158188 const current =
159189 this . enabled &&
160190 request . epoch === this . epoch &&
@@ -177,9 +207,36 @@ export class ProcessingPreviewController {
177207 }
178208
179209 private invalidateSession ( ) : void {
210+ this . releaseCurrentResult ( ) ;
180211 this . epoch += 1 ;
181212 this . revision += 1 ;
182213 this . targetSourceId = null ;
183214 this . coordinator . cancelPending ( this ) ;
184215 }
216+
217+ takeCurrentResult ( ) : string | null {
218+ const candidate = this . currentResult ;
219+ this . currentResult = null ;
220+ if (
221+ ! this . enabled ||
222+ candidate === null ||
223+ candidate . epoch !== this . epoch ||
224+ candidate . revision !== this . revision
225+ ) {
226+ this . releaseToken ( candidate ?. previewToken ?? null ) ;
227+ return null ;
228+ }
229+ return candidate . previewToken ;
230+ }
231+
232+ private releaseCurrentResult ( ) : void {
233+ const token = this . currentResult ?. previewToken ?? null ;
234+ this . currentResult = null ;
235+ this . releaseToken ( token ) ;
236+ }
237+
238+ private releaseToken ( token : string | null ) : void {
239+ if ( token === null ) return ;
240+ void this . runtime . releasePreviewResult ( token ) . catch ( ( ) => undefined ) ;
241+ }
185242}
0 commit comments