33 gesturePayloadToPositionals ,
44 normalizePublicGesture ,
55 normalizePublicSwipeMotion ,
6+ type GestureDeprecation ,
67 type SwipePayload ,
78} from '../../contracts/gesture-normalization.ts' ;
89import { requireGestureSupported } from '../../core/capabilities.ts' ;
@@ -17,139 +18,138 @@ import { readOptionalInteger } from '../../kernel/input-validation.ts';
1718import type { Point } from '../../kernel/snapshot.ts' ;
1819import { isActiveProviderDevice } from '../../provider-device-runtime.ts' ;
1920import { sleep } from '../../utils/timeouts.ts' ;
20- import type { DaemonResponse } from '../types.ts' ;
21+ import type { DaemonResponse , SessionState } from '../types.ts' ;
2122import { ensureAndroidBlockingSystemDialogReady } from '../android-system-dialog.ts' ;
2223import type { InteractionHandlerParams } from './interaction-common.ts' ;
2324import { finalizeTouchInteraction } from './interaction-common.ts' ;
2425import { createInteractionRuntime } from './interaction-runtime.ts' ;
2526import type { CaptureSnapshotForSession } from './interaction-snapshot.ts' ;
2627import { noActiveSessionError } from './response.ts' ;
2728
29+ type GestureHandlerParams = InteractionHandlerParams & {
30+ captureSnapshotForSession : CaptureSnapshotForSession ;
31+ } ;
32+
33+ type GestureRuntime = ReturnType < typeof createInteractionRuntime > ;
34+ type GestureRuntimeResult = Awaited < ReturnType < GestureRuntime [ 'interactions' ] [ 'gesture' ] > > ;
35+
36+ type GestureInteractionOutcome = {
37+ positionals : string [ ] ;
38+ flags : InteractionHandlerParams [ 'req' ] [ 'flags' ] ;
39+ responseData : Record < string , unknown > ;
40+ recordingResultExtra ?: Record < string , unknown > ;
41+ } ;
42+
2843export async function dispatchGestureViaRuntime (
29- params : InteractionHandlerParams & {
30- captureSnapshotForSession : CaptureSnapshotForSession ;
31- } ,
44+ params : GestureHandlerParams ,
3245) : Promise < DaemonResponse > {
33- const session = params . sessionStore . get ( params . sessionName ) ;
34- if ( ! session ) return noActiveSessionError ( ) ;
35- const startedAt = Date . now ( ) ;
36- try {
46+ return await dispatchGestureInteraction ( params , 'gesture' , async ( session ) => {
3747 const input = readGesturePayload ( params . req . input ) ;
3848 const normalized = normalizePublicGesture ( input ) ;
3949 requireGestureSupported ( normalized . gesture , session . device ) ;
40- const providerDevice = isActiveProviderDevice ( session . device ) ;
41- const readiness = providerDevice
42- ? ( { status : 'clear' } as const )
43- : await ensureAndroidBlockingSystemDialogReady ( {
44- session,
45- command : 'gesture' ,
46- phase : 'before-command' ,
47- } ) ;
4850 const result = await createInteractionRuntime ( params ) . interactions . gesture ( {
4951 session : params . sessionName ,
5052 requestId : params . req . meta ?. requestId ,
5153 gesture : normalized . gesture ,
5254 } ) ;
53- if ( ! providerDevice ) {
54- await ensureAndroidBlockingSystemDialogReady ( {
55- session,
56- command : 'gesture' ,
57- phase : 'after-command' ,
58- } ) ;
59- }
60- const responseData : Record < string , unknown > = {
61- kind : result . kind ,
62- durationMs : result . durationMs ,
63- pointerCount : result . pointerCount ,
64- from : result . from ,
65- to : result . to ,
66- ...( result . backendResult ?? { } ) ,
67- ...( normalized . deprecations . length > 0 ? { deprecations : normalized . deprecations } : { } ) ,
68- message : result . message ,
69- } ;
70- if ( readiness . status === 'recovered' ) responseData . warning = readiness . warning ;
71- return finalizeTouchInteraction ( {
72- session,
73- sessionStore : params . sessionStore ,
74- command : 'gesture' ,
75- actionCommand : 'gesture' ,
55+ return {
7656 positionals : gesturePayloadToPositionals ( input ) ,
7757 flags : gestureReplayFlags ( input , params . req . flags ) ,
78- result : {
79- ...responseData ,
80- ...( input . kind === 'pinch' ? { scale : input . scale } : { } ) ,
81- } ,
82- responseData,
83- actionStartedAt : startedAt ,
84- actionFinishedAt : Date . now ( ) ,
85- } ) ;
86- } catch ( error ) {
87- return { ok : false , error : normalizeError ( error ) } ;
88- }
58+ responseData : gestureResponseData ( result , normalized . deprecations ) ,
59+ ...( input . kind === 'pinch' ? { recordingResultExtra : { scale : input . scale } } : { } ) ,
60+ } ;
61+ } ) ;
8962}
9063
9164export async function dispatchSwipeViaRuntime (
92- params : InteractionHandlerParams & {
93- captureSnapshotForSession : CaptureSnapshotForSession ;
94- } ,
65+ params : GestureHandlerParams ,
9566) : Promise < DaemonResponse > {
96- const session = params . sessionStore . get ( params . sessionName ) ;
97- if ( ! session ) return noActiveSessionError ( ) ;
98- const startedAt = Date . now ( ) ;
99- try {
67+ return await dispatchGestureInteraction ( params , 'swipe' , async ( session ) => {
10068 const input = readSwipeInput ( params . req . input ) ;
10169 requireGestureSupported ( normalizePublicSwipeMotion ( input ) . gesture , session . device ) ;
10270 const count = input . count ?? 1 ;
10371 const pauseMs = input . pauseMs ?? 0 ;
10472 const pattern = input . pattern ?? 'one-way' ;
73+ const runtime = createInteractionRuntime ( params ) ;
74+ const result = await runSwipeRepetitions ( runtime , params , input , count , pauseMs , pattern ) ;
75+ return {
76+ positionals : swipeReplayPositionals ( input ) ,
77+ flags : params . req . flags ,
78+ responseData : gestureResponseData ( result , result . deprecations ?? [ ] , {
79+ count,
80+ pauseMs,
81+ pattern,
82+ } ) ,
83+ } ;
84+ } ) ;
85+ }
86+
87+ async function dispatchGestureInteraction (
88+ params : GestureHandlerParams ,
89+ command : 'gesture' | 'swipe' ,
90+ run : ( session : SessionState ) => Promise < GestureInteractionOutcome > ,
91+ ) : Promise < DaemonResponse > {
92+ const session = params . sessionStore . get ( params . sessionName ) ;
93+ if ( ! session ) return noActiveSessionError ( ) ;
94+ const actionStartedAt = Date . now ( ) ;
95+ try {
10596 const providerDevice = isActiveProviderDevice ( session . device ) ;
10697 const readiness = providerDevice
10798 ? ( { status : 'clear' } as const )
10899 : await ensureAndroidBlockingSystemDialogReady ( {
109100 session,
110- command : 'swipe' ,
101+ command,
111102 phase : 'before-command' ,
112103 } ) ;
113- const runtime = createInteractionRuntime ( params ) ;
114- const result = await runSwipeRepetitions ( runtime , params , input , count , pauseMs , pattern ) ;
104+ const outcome = await run ( session ) ;
115105 if ( ! providerDevice ) {
116106 await ensureAndroidBlockingSystemDialogReady ( {
117107 session,
118- command : 'swipe' ,
108+ command,
119109 phase : 'after-command' ,
120110 } ) ;
121111 }
122- const responseData : Record < string , unknown > = {
123- kind : result . kind ,
124- durationMs : result . durationMs ,
125- pointerCount : result . pointerCount ,
126- from : result . from ,
127- to : result . to ,
128- count,
129- pauseMs,
130- pattern,
131- ...( result . backendResult ?? { } ) ,
132- ...( result . deprecations ? { deprecations : result . deprecations } : { } ) ,
133- message : result . message ,
134- } ;
135- if ( readiness . status === 'recovered' ) responseData . warning = readiness . warning ;
112+ const responseData = { ...outcome . responseData } ;
113+ if ( readiness . status === 'recovered' ) {
114+ const existingWarning =
115+ typeof responseData . warning === 'string' ? `${ responseData . warning } ` : '' ;
116+ responseData . warning = `${ existingWarning } ${ readiness . warning } ` ;
117+ }
136118 return finalizeTouchInteraction ( {
137119 session,
138120 sessionStore : params . sessionStore ,
139- command : 'swipe' ,
140- actionCommand : 'swipe' ,
141- positionals : swipeReplayPositionals ( input ) ,
142- flags : params . req . flags ,
143- result : responseData ,
121+ command,
122+ actionCommand : command ,
123+ positionals : outcome . positionals ,
124+ flags : outcome . flags ,
125+ result : { ... responseData , ... ( outcome . recordingResultExtra ?? { } ) } ,
144126 responseData,
145- actionStartedAt : startedAt ,
127+ actionStartedAt,
146128 actionFinishedAt : Date . now ( ) ,
147129 } ) ;
148130 } catch ( error ) {
149131 return { ok : false , error : normalizeError ( error ) } ;
150132 }
151133}
152134
135+ function gestureResponseData (
136+ result : GestureRuntimeResult ,
137+ deprecations : readonly GestureDeprecation [ ] ,
138+ extra : Record < string , unknown > = { } ,
139+ ) : Record < string , unknown > {
140+ return {
141+ kind : result . kind ,
142+ durationMs : result . durationMs ,
143+ pointerCount : result . pointerCount ,
144+ from : result . from ,
145+ to : result . to ,
146+ ...extra ,
147+ ...( result . backendResult ?? { } ) ,
148+ ...( deprecations . length > 0 ? { deprecations } : { } ) ,
149+ message : result . message ,
150+ } ;
151+ }
152+
153153function readSwipeInput ( input : unknown ) : SwipePayload {
154154 if ( ! input || typeof input !== 'object' || Array . isArray ( input ) ) {
155155 throw new AppError ( 'INVALID_ARGS' , 'swipe requires structured object input' ) ;
0 commit comments