or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

activity-completion.mdclient-connection.mderror-handling.mdindex.mdinterceptors.mdschedule-client.mdtask-queue-client.mdworkflow-client.md

interceptors.mddocs/

0

# Interceptors

1

2

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.

3

4

## Capabilities

5

6

### Workflow Client Interceptors

7

8

Interceptors for customizing workflow client operations.

9

10

```typescript { .api }

11

/**

12

* Interceptor for workflow client calls

13

*/

14

interface WorkflowClientInterceptor {

15

/** Intercept workflow start operations */

16

start?(

17

input: WorkflowStartInput,

18

next: WorkflowClientCallsInterceptor['start']

19

): Promise<WorkflowHandle>;

20

21

/** Intercept signal with start operations */

22

signalWithStart?(

23

input: WorkflowSignalWithStartInput,

24

next: WorkflowClientCallsInterceptor['signalWithStart']

25

): Promise<WorkflowHandleWithSignaledRunId>;

26

27

/** Intercept workflow update start operations */

28

startUpdate?(

29

input: WorkflowStartUpdateInput,

30

next: WorkflowClientCallsInterceptor['startUpdate']

31

): Promise<WorkflowStartUpdateOutput>;

32

33

/** Intercept workflow update with start operations */

34

startUpdateWithStart?(

35

input: WorkflowStartUpdateWithStartInput,

36

next: WorkflowClientCallsInterceptor['startUpdateWithStart']

37

): Promise<WorkflowStartUpdateWithStartOutput>;

38

39

/** Intercept signal operations */

40

signal?(

41

input: WorkflowSignalInput,

42

next: WorkflowClientCallsInterceptor['signal']

43

): Promise<void>;

44

45

/** Intercept query operations */

46

query?(

47

input: WorkflowQueryInput,

48

next: WorkflowClientCallsInterceptor['query']

49

): Promise<unknown>;

50

51

/** Intercept workflow termination */

52

terminate?(

53

input: WorkflowTerminateInput,

54

next: WorkflowClientCallsInterceptor['terminate']

55

): Promise<void>;

56

57

/** Intercept workflow cancellation */

58

cancel?(

59

input: WorkflowCancelInput,

60

next: WorkflowClientCallsInterceptor['cancel']

61

): Promise<void>;

62

63

/** Intercept workflow describe operations */

64

describe?(

65

input: WorkflowDescribeInput,

66

next: WorkflowClientCallsInterceptor['describe']

67

): Promise<WorkflowExecutionDescription>;

68

}

69

```

70

71

### Schedule Client Interceptors

72

73

Interceptors for customizing schedule client operations.

74

75

```typescript { .api }

76

/**

77

* Interceptor for schedule client calls

78

*/

79

interface ScheduleClientInterceptor {

80

/** Intercept schedule creation */

81

create?(

82

input: CreateScheduleInput,

83

next: ScheduleClientCallsInterceptor['create']

84

): Promise<CreateScheduleOutput>;

85

}

86

```

87

88

### Combined Client Interceptors

89

90

Interface for providing interceptors for all client types.

91

92

```typescript { .api }

93

/**

94

* Combined interceptors for all clients

95

*/

96

interface ClientInterceptors {

97

/** Workflow client interceptors */

98

workflow?: WorkflowClientInterceptor[];

99

/** Schedule client interceptors */

100

schedule?: ScheduleClientInterceptor[];

101

}

102

```

103

104

### Workflow Interceptor Input/Output Types

105

106

Input and output types for workflow interceptor methods.

107

108

```typescript { .api }

109

/**

110

* Input for workflow start interceptor

111

*/

112

interface WorkflowStartInput {

113

readonly workflowType: string;

114

readonly options: WorkflowStartOptions;

115

readonly headers: Headers;

116

}

117

118

/**

119

* Input for workflow start update interceptor

120

*/

121

interface WorkflowStartUpdateInput {

122

readonly workflowId: string;

123

readonly runId?: string;

124

readonly updateName: string;

125

readonly args: unknown[];

126

readonly options: WorkflowUpdateOptions;

127

readonly headers: Headers;

128

}

129

130

/**

131

* Output for workflow start update interceptor

132

*/

133

interface WorkflowStartUpdateOutput {

134

readonly updateHandle: WorkflowUpdateHandle<unknown>;

135

}

136

137

/**

138

* Input for workflow start update with start interceptor

139

*/

140

interface WorkflowStartUpdateWithStartInput {

141

readonly workflowType: string;

142

readonly workflowStartOptions: WorkflowStartOptions;

143

readonly updateName: string;

144

readonly updateArgs: unknown[];

145

readonly updateOptions: WorkflowUpdateOptions;

146

readonly headers: Headers;

147

}

148

149

/**

150

* Output for workflow start update with start interceptor

151

*/

152

interface WorkflowStartUpdateWithStartOutput {

153

readonly updateHandle: WorkflowUpdateHandle<unknown>;

154

readonly workflowHandle: WorkflowHandle<unknown>;

155

}

156

157

/**

158

* Input for workflow signal interceptor

159

*/

160

interface WorkflowSignalInput {

161

readonly workflowId: string;

162

readonly runId?: string;

163

readonly signalName: string;

164

readonly args: unknown[];

165

readonly headers: Headers;

166

}

167

168

/**

169

* Input for workflow signal with start interceptor

170

*/

171

interface WorkflowSignalWithStartInput {

172

readonly workflowType: string;

173

readonly workflowStartOptions: WorkflowStartOptions;

174

readonly signalName: string;

175

readonly signalArgs: unknown[];

176

readonly headers: Headers;

177

}

178

179

/**

180

* Input for workflow query interceptor

181

*/

182

interface WorkflowQueryInput {

183

readonly workflowId: string;

184

readonly runId?: string;

185

readonly queryType: string;

186

readonly args: unknown[];

187

readonly queryRejectCondition?: QueryRejectCondition;

188

readonly headers: Headers;

189

}

190

191

/**

192

* Input for workflow terminate interceptor

193

*/

194

interface WorkflowTerminateInput {

195

readonly workflowId: string;

196

readonly runId?: string;

197

readonly reason?: string;

198

readonly headers: Headers;

199

}

200

201

/**

202

* Input for workflow cancel interceptor

203

*/

204

interface WorkflowCancelInput {

205

readonly workflowId: string;

206

readonly runId?: string;

207

readonly headers: Headers;

208

}

209

210

/**

211

* Input for workflow describe interceptor

212

*/

213

interface WorkflowDescribeInput {

214

readonly workflowId: string;

215

readonly runId?: string;

216

readonly headers: Headers;

217

}

218

```

219

220

### Schedule Interceptor Input/Output Types

221

222

Input and output types for schedule interceptor methods.

223

224

```typescript { .api }

225

/**

226

* Input for create schedule interceptor

227

*/

228

interface CreateScheduleInput {

229

readonly scheduleId: string;

230

readonly schedule: ScheduleOptions;

231

readonly headers: Headers;

232

}

233

234

/**

235

* Output for create schedule interceptor

236

*/

237

interface CreateScheduleOutput {

238

readonly scheduleHandle: ScheduleHandle;

239

}

240

```

241

242

## Usage Examples

243

244

### Logging Interceptor

245

246

```typescript

247

import { WorkflowClientInterceptor } from "@temporalio/client";

248

249

class LoggingInterceptor implements WorkflowClientInterceptor {

250

async start(input, next) {

251

console.log(`Starting workflow: ${input.workflowType} (ID: ${input.options.workflowId})`);

252

const startTime = Date.now();

253

254

try {

255

const handle = await next(input);

256

console.log(`Workflow started successfully in ${Date.now() - startTime}ms`);

257

return handle;

258

} catch (error) {

259

console.error(`Failed to start workflow: ${error}`);

260

throw error;

261

}

262

}

263

264

async signal(input, next) {

265

console.log(`Sending signal: ${input.signalName} to workflow ${input.workflowId}`);

266

return await next(input);

267

}

268

269

async query(input, next) {

270

console.log(`Querying workflow: ${input.queryType} on ${input.workflowId}`);

271

const result = await next(input);

272

console.log(`Query result:`, result);

273

return result;

274

}

275

}

276

277

// Usage

278

const client = new Client({

279

interceptors: {

280

workflow: [new LoggingInterceptor()],

281

},

282

});

283

```

284

285

### Metrics Interceptor

286

287

```typescript

288

interface MetricsCollector {

289

increment(metric: string, tags?: Record<string, string>): void;

290

timing(metric: string, duration: number, tags?: Record<string, string>): void;

291

}

292

293

class MetricsInterceptor implements WorkflowClientInterceptor {

294

constructor(private metrics: MetricsCollector) {}

295

296

async start(input, next) {

297

const tags = { workflow_type: input.workflowType };

298

const startTime = Date.now();

299

300

try {

301

const handle = await next(input);

302

this.metrics.increment('workflow.start.success', tags);

303

this.metrics.timing('workflow.start.duration', Date.now() - startTime, tags);

304

return handle;

305

} catch (error) {

306

this.metrics.increment('workflow.start.failure', tags);

307

throw error;

308

}

309

}

310

311

async signal(input, next) {

312

const tags = { signal_name: input.signalName };

313

this.metrics.increment('workflow.signal.sent', tags);

314

return await next(input);

315

}

316

317

async query(input, next) {

318

const tags = { query_type: input.queryType };

319

const startTime = Date.now();

320

321

try {

322

const result = await next(input);

323

this.metrics.increment('workflow.query.success', tags);

324

this.metrics.timing('workflow.query.duration', Date.now() - startTime, tags);

325

return result;

326

} catch (error) {

327

this.metrics.increment('workflow.query.failure', tags);

328

throw error;

329

}

330

}

331

}

332

```

333

334

### Authentication Interceptor

335

336

```typescript

337

class AuthInterceptor implements WorkflowClientInterceptor {

338

constructor(private getAuthToken: () => Promise<string>) {}

339

340

async start(input, next) {

341

const token = await this.getAuthToken();

342

const enhancedInput = {

343

...input,

344

headers: {

345

...input.headers,

346

authorization: `Bearer ${token}`,

347

},

348

};

349

return await next(enhancedInput);

350

}

351

352

async signal(input, next) {

353

const token = await this.getAuthToken();

354

const enhancedInput = {

355

...input,

356

headers: {

357

...input.headers,

358

authorization: `Bearer ${token}`,

359

},

360

};

361

return await next(enhancedInput);

362

}

363

364

async query(input, next) {

365

const token = await this.getAuthToken();

366

const enhancedInput = {

367

...input,

368

headers: {

369

...input.headers,

370

authorization: `Bearer ${token}`,

371

},

372

};

373

return await next(enhancedInput);

374

}

375

}

376

```

377

378

### Request Transformation Interceptor

379

380

```typescript

381

class RequestTransformInterceptor implements WorkflowClientInterceptor {

382

async start(input, next) {

383

// Transform workflow options based on environment

384

const transformedOptions = {

385

...input.options,

386

taskQueue: this.transformTaskQueue(input.options.taskQueue),

387

memo: {

388

...input.options.memo,

389

environment: process.env.NODE_ENV,

390

version: process.env.APP_VERSION,

391

},

392

};

393

394

return await next({

395

...input,

396

options: transformedOptions,

397

});

398

}

399

400

private transformTaskQueue(originalQueue: string): string {

401

const env = process.env.NODE_ENV || 'development';

402

return env === 'production' ? originalQueue : `${env}-${originalQueue}`;

403

}

404

}

405

```

406

407

### Retry Interceptor

408

409

```typescript

410

class RetryInterceptor implements WorkflowClientInterceptor {

411

constructor(

412

private maxRetries: number = 3,

413

private baseDelay: number = 1000

414

) {}

415

416

async start(input, next) {

417

return await this.withRetry(() => next(input));

418

}

419

420

async signal(input, next) {

421

return await this.withRetry(() => next(input));

422

}

423

424

async query(input, next) {

425

return await this.withRetry(() => next(input));

426

}

427

428

private async withRetry<T>(operation: () => Promise<T>): Promise<T> {

429

let lastError: Error;

430

431

for (let attempt = 0; attempt <= this.maxRetries; attempt++) {

432

try {

433

return await operation();

434

} catch (error) {

435

lastError = error as Error;

436

437

// Don't retry on client errors

438

if (error instanceof WorkflowFailedError) {

439

throw error;

440

}

441

442

if (attempt < this.maxRetries) {

443

const delay = this.baseDelay * Math.pow(2, attempt);

444

await new Promise(resolve => setTimeout(resolve, delay));

445

continue;

446

}

447

448

throw error;

449

}

450

}

451

452

throw lastError!;

453

}

454

}

455

```

456

457

### Combined Interceptor Usage

458

459

```typescript

460

import { Client } from "@temporalio/client";

461

462

// Create multiple interceptors

463

const loggingInterceptor = new LoggingInterceptor();

464

const metricsInterceptor = new MetricsInterceptor(metricsCollector);

465

const authInterceptor = new AuthInterceptor(getAuthToken);

466

const retryInterceptor = new RetryInterceptor(3, 1000);

467

468

// Create client with multiple interceptors

469

const client = new Client({

470

interceptors: {

471

workflow: [

472

loggingInterceptor,

473

metricsInterceptor,

474

authInterceptor,

475

retryInterceptor,

476

],

477

schedule: [], // Add schedule interceptors if needed

478

},

479

});

480

481

// Interceptors are applied in order, creating a chain

482

```

483

484

### Schedule Interceptor Example

485

486

```typescript

487

class ScheduleLoggingInterceptor implements ScheduleClientInterceptor {

488

async create(input, next) {

489

console.log(`Creating schedule: ${input.scheduleId}`);

490

console.log(`Schedule spec:`, input.schedule.spec);

491

492

try {

493

const result = await next(input);

494

console.log(`Schedule ${input.scheduleId} created successfully`);

495

return result;

496

} catch (error) {

497

console.error(`Failed to create schedule ${input.scheduleId}:`, error);

498

throw error;

499

}

500

}

501

}

502

503

// Usage with schedule interceptor

504

const client = new Client({

505

interceptors: {

506

schedule: [new ScheduleLoggingInterceptor()],

507

},

508

});

509

```