@@ -11,6 +11,8 @@ import type {
1111 WorkflowResultType ,
1212 WorkflowIdConflictPolicy ,
1313 WorkflowSerializationContext ,
14+ WorkflowTypeOptions ,
15+ PayloadTypeInfo ,
1416} from '@temporalio/common' ;
1517import {
1618 CancelledFailure ,
@@ -21,11 +23,11 @@ import {
2123 TimeoutType ,
2224 WorkflowExecutionAlreadyStartedError ,
2325 WorkflowNotFoundError ,
24- extractWorkflowType ,
2526 encodeWorkflowIdReusePolicy ,
2627 decodeRetryState ,
2728 encodeWorkflowIdConflictPolicy ,
2829 compilePriority ,
30+ extractWorkflowTypeAndConfig ,
2931} from '@temporalio/common' ;
3032import { encodeUserMetadata } from '@temporalio/common/lib/internal-non-workflow/codec-helpers' ;
3133import { encodeUnifiedSearchAttributes } from '@temporalio/common/lib/converter/payload-search-attributes' ;
@@ -360,6 +362,16 @@ export interface WorkflowResultOptions {
360362 * @default true
361363 */
362364 followRuns ?: boolean ;
365+
366+ /**
367+ * Type information used to decode the Workflow result.
368+ *
369+ * This is only needed when getting a result from an existing Workflow handle or
370+ * when the Workflow definition is not available to this client.
371+ *
372+ * @experimental
373+ */
374+ typeInfo ?: PayloadTypeInfo ;
363375}
364376
365377/**
@@ -550,13 +562,16 @@ export class WorkflowClient extends BaseClient {
550562 }
551563
552564 protected async _start < T extends Workflow > (
553- workflowTypeOrFunc : string | T ,
565+ workflowTypeOptions : WorkflowTypeOptions ,
554566 options : WorkflowStartOptions < T > ,
555567 interceptors : WorkflowClientInterceptor [ ]
556568 ) : Promise < WorkflowStartOutput > {
557- const workflowType = extractWorkflowType ( workflowTypeOrFunc ) ;
558569 assertRequiredWorkflowOptions ( options ) ;
559- const compiledOptions = compileWorkflowOptions ( ensureArgs ( options ) ) ;
570+ const workflowOptions = {
571+ ...options ,
572+ typeInfo : workflowTypeOptions . typeInfo ,
573+ } ;
574+ const compiledOptions = compileWorkflowOptions ( ensureArgs ( workflowOptions ) ) ;
560575 const adaptedInterceptors = interceptors . map ( ( i ) => adaptWorkflowClientInterceptor ( i ) ) ;
561576
562577 const startWithDetails = composeInterceptors (
@@ -568,7 +583,7 @@ export class WorkflowClient extends BaseClient {
568583 return startWithDetails ( {
569584 options : compiledOptions ,
570585 headers : { } ,
571- workflowType,
586+ workflowType : workflowTypeOptions . type ,
572587 } ) ;
573588 }
574589
@@ -577,10 +592,14 @@ export class WorkflowClient extends BaseClient {
577592 options : WithWorkflowArgs < T , WorkflowSignalWithStartOptions < SA > > ,
578593 interceptors : WorkflowClientInterceptor [ ]
579594 ) : Promise < string > {
580- const workflowType = extractWorkflowType ( workflowTypeOrFunc ) ;
581595 const { signal, signalArgs, ...rest } = options ;
596+ const { type : workflowType , typeInfo } = extractWorkflowTypeAndConfig ( workflowTypeOrFunc , rest . typeInfo ) ;
582597 assertRequiredWorkflowOptions ( rest ) ;
583- const compiledOptions = compileWorkflowOptions ( ensureArgs ( rest ) ) ;
598+ const workflowOptions = {
599+ ...rest ,
600+ typeInfo,
601+ } ;
602+ const compiledOptions = compileWorkflowOptions ( ensureArgs ( workflowOptions ) ) ;
584603 const signalWithStart = composeInterceptors (
585604 interceptors ,
586605 'signalWithStart' ,
@@ -607,7 +626,8 @@ export class WorkflowClient extends BaseClient {
607626 ) : Promise < WorkflowHandleWithStartDetails < T > > {
608627 const { workflowId } = options ;
609628 const interceptors = this . getOrMakeInterceptors ( workflowId ) ;
610- const wfStartOutput = await this . _start ( workflowTypeOrFunc , { ...options , workflowId } , interceptors ) ;
629+ const workflowTypeOptions = extractWorkflowTypeAndConfig ( workflowTypeOrFunc , options . typeInfo ) ;
630+ const wfStartOutput = await this . _start ( workflowTypeOptions , { ...options , workflowId } , interceptors ) ;
611631 // runId is not used in handles created with `start*` calls because these
612632 // handles should allow interacting with the workflow if it continues as new.
613633 const baseHandle = this . _createWorkflowHandle ( {
@@ -617,6 +637,7 @@ export class WorkflowClient extends BaseClient {
617637 runIdForResult : wfStartOutput . runId ,
618638 interceptors,
619639 followRuns : options . followRuns ?? true ,
640+ typeInfo : workflowTypeOptions . typeInfo ,
620641 } ) ;
621642 return {
622643 ...baseHandle ,
@@ -642,6 +663,7 @@ export class WorkflowClient extends BaseClient {
642663 ) : Promise < WorkflowHandleWithSignaledRunId < WorkflowFn > > {
643664 const { workflowId } = options ;
644665 const interceptors = this . getOrMakeInterceptors ( workflowId ) ;
666+ const workflowTypeOptions = extractWorkflowTypeAndConfig ( workflowTypeOrFunc , options . typeInfo ) ;
645667 const runId = await this . _signalWithStart ( workflowTypeOrFunc , options , interceptors ) ;
646668 // runId is not used in handles created with `start*` calls because these
647669 // handles should allow interacting with the workflow if it continues as new.
@@ -652,6 +674,7 @@ export class WorkflowClient extends BaseClient {
652674 runIdForResult : runId ,
653675 interceptors,
654676 followRuns : options . followRuns ?? true ,
677+ typeInfo : workflowTypeOptions . typeInfo ,
655678 } ) as WorkflowHandleWithSignaledRunId < WorkflowFn > ; // Cast is safe because we know we add the signaledRunId below
656679 ( handle as any ) /* readonly */ . signaledRunId = runId ;
657680 return handle ;
@@ -736,11 +759,16 @@ export class WorkflowClient extends BaseClient {
736759 throw new Error ( 'This WithStartWorkflowOperation instance has already been executed.' ) ;
737760 }
738761 startWorkflowOperation [ withStartWorkflowOperationUsed ] = true ;
762+ const { type : workflowType , typeInfo } = extractWorkflowTypeAndConfig ( workflowTypeOrFunc , workflowOptions . typeInfo ) ;
739763 assertRequiredWorkflowOptions ( workflowOptions ) ;
740764
765+ const resolvedWorkflowOptions = {
766+ ...workflowOptions ,
767+ typeInfo,
768+ } ;
741769 const startUpdateWithStartInput : WorkflowStartUpdateWithStartInput = {
742- workflowType : extractWorkflowType ( workflowTypeOrFunc ) ,
743- workflowStartOptions : compileWorkflowOptions ( ensureArgs ( workflowOptions ) ) ,
770+ workflowType,
771+ workflowStartOptions : compileWorkflowOptions ( ensureArgs ( resolvedWorkflowOptions ) ) ,
744772 workflowStartHeaders : { } ,
745773 updateName : typeof updateDef === 'string' ? updateDef : updateDef . name ,
746774 updateArgs : args ?? [ ] ,
@@ -757,6 +785,7 @@ export class WorkflowClient extends BaseClient {
757785 firstExecutionRunId : startResponse . runId ?? undefined ,
758786 interceptors,
759787 followRuns : workflowOptions . followRuns ?? true ,
788+ typeInfo,
760789 } )
761790 ) ;
762791
@@ -798,10 +827,12 @@ export class WorkflowClient extends BaseClient {
798827 ) : Promise < WorkflowResultType < T > > {
799828 const { workflowId } = options ;
800829 const interceptors = this . getOrMakeInterceptors ( workflowId ) ;
801- await this . _start ( workflowTypeOrFunc , options , interceptors ) ;
830+ const workflowTypeOptions = extractWorkflowTypeAndConfig ( workflowTypeOrFunc , options . typeInfo ) ;
831+ await this . _start ( workflowTypeOptions , options , interceptors ) ;
802832 return await this . result ( workflowId , undefined , {
803833 ...options ,
804834 followRuns : options . followRuns ?? true ,
835+ typeInfo : workflowTypeOptions . typeInfo ,
805836 } ) ;
806837 }
807838
@@ -857,12 +888,14 @@ export class WorkflowClient extends BaseClient {
857888 }
858889 // Note that we can only return one value from our workflow function in JS.
859890 // Ignore any other payloads in result
860- const [ result ] = await decodeArrayFromPayloads (
891+ const result = await decodeFromPayloadsAtIndex < WorkflowResultType < T > > (
861892 dataConverter ,
893+ 0 ,
862894 ev . workflowExecutionCompletedEventAttributes . result ?. payloads ,
863- context
895+ context ,
896+ opts ?. typeInfo ?. outputType
864897 ) ;
865- return result as any ;
898+ return result ;
866899 } else if ( ev . workflowExecutionFailedEventAttributes ) {
867900 if ( followRuns && ev . workflowExecutionFailedEventAttributes . newExecutionRunId ) {
868901 execution . runId = ev . workflowExecutionFailedEventAttributes . newExecutionRunId ;
@@ -1335,7 +1368,9 @@ export class WorkflowClient extends BaseClient {
13351368 workflowIdReusePolicy : encodeWorkflowIdReusePolicy ( options . workflowIdReusePolicy ) ,
13361369 workflowIdConflictPolicy : encodeWorkflowIdConflictPolicy ( options . workflowIdConflictPolicy ) ,
13371370 workflowType : { name : workflowType } ,
1338- input : { payloads : await encodeToPayloadsWithContext ( dataConverter , context , options . args ) } ,
1371+ input : {
1372+ payloads : await encodeToPayloadsWithContext ( dataConverter , context , options . args , options . typeInfo ?. inputTypes ) ,
1373+ } ,
13391374 signalName,
13401375 signalInput : { payloads : await encodeToPayloadsWithContext ( dataConverter , context , signalArgs ) } ,
13411376 taskQueue : {
@@ -1465,7 +1500,9 @@ export class WorkflowClient extends BaseClient {
14651500 workflowIdReusePolicy : encodeWorkflowIdReusePolicy ( opts . workflowIdReusePolicy ) ,
14661501 workflowIdConflictPolicy : encodeWorkflowIdConflictPolicy ( opts . workflowIdConflictPolicy ) ,
14671502 workflowType : { name : workflowType } ,
1468- input : { payloads : await encodeToPayloadsWithContext ( dataConverter , context , opts . args ) } ,
1503+ input : {
1504+ payloads : await encodeToPayloadsWithContext ( dataConverter , context , opts . args , opts . typeInfo ?. inputTypes ) ,
1505+ } ,
14691506 taskQueue : {
14701507 kind : temporal . api . enums . v1 . TaskQueueKind . TASK_QUEUE_KIND_NORMAL ,
14711508 name : opts . taskQueue ,
@@ -1752,6 +1789,7 @@ export class WorkflowClient extends BaseClient {
17521789 runIdForResult : runId ?? options ?. firstExecutionRunId ,
17531790 interceptors,
17541791 followRuns : options ?. followRuns ?? true ,
1792+ typeInfo : options ?. typeInfo ,
17551793 } ) ;
17561794 }
17571795
0 commit comments