TypeScript SDK Client for communicating with Temporal workflow orchestration systems, providing workflow lifecycle management, connection handling, and durable execution patterns.
Pluggable system for customizing client behavior through interceptors that can modify requests, responses, and add cross-cutting concerns like logging, metrics, authentication, and request transformation.
Interceptors for customizing workflow client operations.
/**
* Interceptor for workflow client calls
*/
interface WorkflowClientInterceptor {
/** Intercept workflow start operations */
start?(
input: WorkflowStartInput,
next: WorkflowClientCallsInterceptor['start']
): Promise<WorkflowHandle>;
/** Intercept signal with start operations */
signalWithStart?(
input: WorkflowSignalWithStartInput,
next: WorkflowClientCallsInterceptor['signalWithStart']
): Promise<WorkflowHandleWithSignaledRunId>;
/** Intercept workflow update start operations */
startUpdate?(
input: WorkflowStartUpdateInput,
next: WorkflowClientCallsInterceptor['startUpdate']
): Promise<WorkflowStartUpdateOutput>;
/** Intercept workflow update with start operations */
startUpdateWithStart?(
input: WorkflowStartUpdateWithStartInput,
next: WorkflowClientCallsInterceptor['startUpdateWithStart']
): Promise<WorkflowStartUpdateWithStartOutput>;
/** Intercept signal operations */
signal?(
input: WorkflowSignalInput,
next: WorkflowClientCallsInterceptor['signal']
): Promise<void>;
/** Intercept query operations */
query?(
input: WorkflowQueryInput,
next: WorkflowClientCallsInterceptor['query']
): Promise<unknown>;
/** Intercept workflow termination */
terminate?(
input: WorkflowTerminateInput,
next: WorkflowClientCallsInterceptor['terminate']
): Promise<void>;
/** Intercept workflow cancellation */
cancel?(
input: WorkflowCancelInput,
next: WorkflowClientCallsInterceptor['cancel']
): Promise<void>;
/** Intercept workflow describe operations */
describe?(
input: WorkflowDescribeInput,
next: WorkflowClientCallsInterceptor['describe']
): Promise<WorkflowExecutionDescription>;
}Interceptors for customizing schedule client operations.
/**
* Interceptor for schedule client calls
*/
interface ScheduleClientInterceptor {
/** Intercept schedule creation */
create?(
input: CreateScheduleInput,
next: ScheduleClientCallsInterceptor['create']
): Promise<CreateScheduleOutput>;
}Interface for providing interceptors for all client types.
/**
* Combined interceptors for all clients
*/
interface ClientInterceptors {
/** Workflow client interceptors */
workflow?: WorkflowClientInterceptor[];
/** Schedule client interceptors */
schedule?: ScheduleClientInterceptor[];
}Input and output types for workflow interceptor methods.
/**
* Input for workflow start interceptor
*/
interface WorkflowStartInput {
readonly workflowType: string;
readonly options: WorkflowStartOptions;
readonly headers: Headers;
}
/**
* Input for workflow start update interceptor
*/
interface WorkflowStartUpdateInput {
readonly workflowId: string;
readonly runId?: string;
readonly updateName: string;
readonly args: unknown[];
readonly options: WorkflowUpdateOptions;
readonly headers: Headers;
}
/**
* Output for workflow start update interceptor
*/
interface WorkflowStartUpdateOutput {
readonly updateHandle: WorkflowUpdateHandle<unknown>;
}
/**
* Input for workflow start update with start interceptor
*/
interface WorkflowStartUpdateWithStartInput {
readonly workflowType: string;
readonly workflowStartOptions: WorkflowStartOptions;
readonly updateName: string;
readonly updateArgs: unknown[];
readonly updateOptions: WorkflowUpdateOptions;
readonly headers: Headers;
}
/**
* Output for workflow start update with start interceptor
*/
interface WorkflowStartUpdateWithStartOutput {
readonly updateHandle: WorkflowUpdateHandle<unknown>;
readonly workflowHandle: WorkflowHandle<unknown>;
}
/**
* Input for workflow signal interceptor
*/
interface WorkflowSignalInput {
readonly workflowId: string;
readonly runId?: string;
readonly signalName: string;
readonly args: unknown[];
readonly headers: Headers;
}
/**
* Input for workflow signal with start interceptor
*/
interface WorkflowSignalWithStartInput {
readonly workflowType: string;
readonly workflowStartOptions: WorkflowStartOptions;
readonly signalName: string;
readonly signalArgs: unknown[];
readonly headers: Headers;
}
/**
* Input for workflow query interceptor
*/
interface WorkflowQueryInput {
readonly workflowId: string;
readonly runId?: string;
readonly queryType: string;
readonly args: unknown[];
readonly queryRejectCondition?: QueryRejectCondition;
readonly headers: Headers;
}
/**
* Input for workflow terminate interceptor
*/
interface WorkflowTerminateInput {
readonly workflowId: string;
readonly runId?: string;
readonly reason?: string;
readonly headers: Headers;
}
/**
* Input for workflow cancel interceptor
*/
interface WorkflowCancelInput {
readonly workflowId: string;
readonly runId?: string;
readonly headers: Headers;
}
/**
* Input for workflow describe interceptor
*/
interface WorkflowDescribeInput {
readonly workflowId: string;
readonly runId?: string;
readonly headers: Headers;
}Input and output types for schedule interceptor methods.
/**
* Input for create schedule interceptor
*/
interface CreateScheduleInput {
readonly scheduleId: string;
readonly schedule: ScheduleOptions;
readonly headers: Headers;
}
/**
* Output for create schedule interceptor
*/
interface CreateScheduleOutput {
readonly scheduleHandle: ScheduleHandle;
}import { WorkflowClientInterceptor } from "@temporalio/client";
class LoggingInterceptor implements WorkflowClientInterceptor {
async start(input, next) {
console.log(`Starting workflow: ${input.workflowType} (ID: ${input.options.workflowId})`);
const startTime = Date.now();
try {
const handle = await next(input);
console.log(`Workflow started successfully in ${Date.now() - startTime}ms`);
return handle;
} catch (error) {
console.error(`Failed to start workflow: ${error}`);
throw error;
}
}
async signal(input, next) {
console.log(`Sending signal: ${input.signalName} to workflow ${input.workflowId}`);
return await next(input);
}
async query(input, next) {
console.log(`Querying workflow: ${input.queryType} on ${input.workflowId}`);
const result = await next(input);
console.log(`Query result:`, result);
return result;
}
}
// Usage
const client = new Client({
interceptors: {
workflow: [new LoggingInterceptor()],
},
});interface MetricsCollector {
increment(metric: string, tags?: Record<string, string>): void;
timing(metric: string, duration: number, tags?: Record<string, string>): void;
}
class MetricsInterceptor implements WorkflowClientInterceptor {
constructor(private metrics: MetricsCollector) {}
async start(input, next) {
const tags = { workflow_type: input.workflowType };
const startTime = Date.now();
try {
const handle = await next(input);
this.metrics.increment('workflow.start.success', tags);
this.metrics.timing('workflow.start.duration', Date.now() - startTime, tags);
return handle;
} catch (error) {
this.metrics.increment('workflow.start.failure', tags);
throw error;
}
}
async signal(input, next) {
const tags = { signal_name: input.signalName };
this.metrics.increment('workflow.signal.sent', tags);
return await next(input);
}
async query(input, next) {
const tags = { query_type: input.queryType };
const startTime = Date.now();
try {
const result = await next(input);
this.metrics.increment('workflow.query.success', tags);
this.metrics.timing('workflow.query.duration', Date.now() - startTime, tags);
return result;
} catch (error) {
this.metrics.increment('workflow.query.failure', tags);
throw error;
}
}
}class AuthInterceptor implements WorkflowClientInterceptor {
constructor(private getAuthToken: () => Promise<string>) {}
async start(input, next) {
const token = await this.getAuthToken();
const enhancedInput = {
...input,
headers: {
...input.headers,
authorization: `Bearer ${token}`,
},
};
return await next(enhancedInput);
}
async signal(input, next) {
const token = await this.getAuthToken();
const enhancedInput = {
...input,
headers: {
...input.headers,
authorization: `Bearer ${token}`,
},
};
return await next(enhancedInput);
}
async query(input, next) {
const token = await this.getAuthToken();
const enhancedInput = {
...input,
headers: {
...input.headers,
authorization: `Bearer ${token}`,
},
};
return await next(enhancedInput);
}
}class RequestTransformInterceptor implements WorkflowClientInterceptor {
async start(input, next) {
// Transform workflow options based on environment
const transformedOptions = {
...input.options,
taskQueue: this.transformTaskQueue(input.options.taskQueue),
memo: {
...input.options.memo,
environment: process.env.NODE_ENV,
version: process.env.APP_VERSION,
},
};
return await next({
...input,
options: transformedOptions,
});
}
private transformTaskQueue(originalQueue: string): string {
const env = process.env.NODE_ENV || 'development';
return env === 'production' ? originalQueue : `${env}-${originalQueue}`;
}
}class RetryInterceptor implements WorkflowClientInterceptor {
constructor(
private maxRetries: number = 3,
private baseDelay: number = 1000
) {}
async start(input, next) {
return await this.withRetry(() => next(input));
}
async signal(input, next) {
return await this.withRetry(() => next(input));
}
async query(input, next) {
return await this.withRetry(() => next(input));
}
private async withRetry<T>(operation: () => Promise<T>): Promise<T> {
let lastError: Error;
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error as Error;
// Don't retry on client errors
if (error instanceof WorkflowFailedError) {
throw error;
}
if (attempt < this.maxRetries) {
const delay = this.baseDelay * Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
throw lastError!;
}
}import { Client } from "@temporalio/client";
// Create multiple interceptors
const loggingInterceptor = new LoggingInterceptor();
const metricsInterceptor = new MetricsInterceptor(metricsCollector);
const authInterceptor = new AuthInterceptor(getAuthToken);
const retryInterceptor = new RetryInterceptor(3, 1000);
// Create client with multiple interceptors
const client = new Client({
interceptors: {
workflow: [
loggingInterceptor,
metricsInterceptor,
authInterceptor,
retryInterceptor,
],
schedule: [], // Add schedule interceptors if needed
},
});
// Interceptors are applied in order, creating a chainclass ScheduleLoggingInterceptor implements ScheduleClientInterceptor {
async create(input, next) {
console.log(`Creating schedule: ${input.scheduleId}`);
console.log(`Schedule spec:`, input.schedule.spec);
try {
const result = await next(input);
console.log(`Schedule ${input.scheduleId} created successfully`);
return result;
} catch (error) {
console.error(`Failed to create schedule ${input.scheduleId}:`, error);
throw error;
}
}
}
// Usage with schedule interceptor
const client = new Client({
interceptors: {
schedule: [new ScheduleLoggingInterceptor()],
},
});Install with Tessl CLI
npx tessl i tessl/npm-temporalio--client