nestjs-temporal-core 3.0.3 → 3.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,10 @@ A comprehensive NestJS integration for [Temporal.io](https://temporal.io/) that
10
10
 
11
11
  NestJS Temporal Core brings Temporal's durable execution to NestJS with familiar decorator patterns and automatic discovery. Build reliable distributed systems with activities and scheduled tasks using native NestJS conventions.
12
12
 
13
+ ## 💡 Example Repository
14
+
15
+ 🔗 **[Complete Example Project](https://github.com/harsh-simform/nestjs-temporal-core-example)** - Check out our full working example repository to see NestJS Temporal Core in action with real-world use cases, configuration examples, and best practices.
16
+
13
17
  ## 🚀 Key Features
14
18
 
15
19
  - **🎯 NestJS-Native** - Familiar patterns: `@Activity`, `@Cron`, `@Interval`
@@ -19,7 +23,8 @@ NestJS Temporal Core brings Temporal's durable execution to NestJS with familiar
19
23
  - **⚙️ Flexible Setup** - Client-only, worker-only, or unified deployments
20
24
  - **🏥 Health Monitoring** - Comprehensive status monitoring and health checks
21
25
  - **🔧 Production Ready** - TLS, connection management, graceful shutdowns
22
- - **📊 Complete Integration** - Full-featured module architecture
26
+ - **📊 Modular Architecture** - Individual modules for specific needs
27
+ - **🔐 Enterprise Ready** - Temporal Cloud support with TLS and API keys
23
28
 
24
29
  ## 📦 Installation
25
30
 
@@ -29,7 +34,9 @@ npm install nestjs-temporal-core @temporalio/client @temporalio/worker @temporal
29
34
 
30
35
  ## 🚀 Quick Start
31
36
 
32
- ### 1. Module Setup
37
+ ### 1. Complete Integration (Recommended)
38
+
39
+ For applications that need full Temporal functionality:
33
40
 
34
41
  ```typescript
35
42
  // app.module.ts
@@ -44,294 +51,505 @@ import { EmailActivities } from './activities/email.activities';
44
51
  address: 'localhost:7233',
45
52
  namespace: 'default',
46
53
  },
47
- taskQueue: 'my-app',
54
+ taskQueue: 'main-queue',
48
55
  worker: {
49
56
  workflowsPath: './dist/workflows',
50
- activityClasses: [EmailActivities], // Auto-discovered
51
- },
52
- }),
57
+ activityClasses: [EmailActivities],
58
+ autoStart: true
59
+ }
60
+ })
53
61
  ],
54
- providers: [EmailActivities],
62
+ providers: [EmailActivities], // Auto-discovered
55
63
  })
56
64
  export class AppModule {}
57
65
  ```
58
66
 
59
- ### 2. Create Activities
67
+ ### 2. Define Activities
60
68
 
61
69
  ```typescript
62
70
  // activities/email.activities.ts
63
71
  import { Injectable } from '@nestjs/common';
64
72
  import { Activity, ActivityMethod } from 'nestjs-temporal-core';
65
73
 
66
- @Injectable()
67
74
  @Activity()
75
+ @Injectable()
68
76
  export class EmailActivities {
69
- @ActivityMethod()
70
- async sendWelcomeEmail(email: string, name: string): Promise<boolean> {
71
- console.log(`Sending welcome email to ${email}`);
72
- // Your email logic here
73
- return true;
77
+
78
+ @ActivityMethod({
79
+ name: 'sendEmail',
80
+ timeout: '30s',
81
+ maxRetries: 3
82
+ })
83
+ async sendEmail(to: string, subject: string, body: string): Promise<void> {
84
+ console.log(`Sending email to ${to}: ${subject}`);
85
+ // Your email sending logic here
74
86
  }
75
87
 
76
- @ActivityMethod()
77
- async sendNotification(email: string, message: string): Promise<void> {
78
- console.log(`Notification to ${email}: ${message}`);
88
+ @ActivityMethod('sendNotification')
89
+ async sendNotification(userId: string, message: string): Promise<void> {
90
+ console.log(`Notifying user ${userId}: ${message}`);
79
91
  // Your notification logic here
80
92
  }
81
93
  }
82
94
  ```
83
95
 
84
- ### 3. Create Scheduled Workflows
96
+ ### 3. Create Workflows
97
+
98
+ ```typescript
99
+ // workflows/email.workflow.ts
100
+ import { proxyActivities } from '@temporalio/workflow';
101
+ import type { EmailActivities } from '../activities/email.activities';
102
+
103
+ const { sendEmail, sendNotification } = proxyActivities<EmailActivities>({
104
+ startToCloseTimeout: '1 minute',
105
+ });
106
+
107
+ export async function processEmailWorkflow(
108
+ userId: string,
109
+ emailData: { to: string; subject: string; body: string }
110
+ ): Promise<void> {
111
+ // Send email
112
+ await sendEmail(emailData.to, emailData.subject, emailData.body);
113
+
114
+ // Send notification
115
+ await sendNotification(userId, 'Email sent successfully');
116
+ }
117
+ ```
118
+
119
+ ### 4. Schedule Workflows
85
120
 
86
121
  ```typescript
87
122
  // services/scheduled.service.ts
88
123
  import { Injectable } from '@nestjs/common';
89
- import { Cron, Interval } from 'nestjs-temporal-core';
124
+ import { Scheduled, Cron, Interval, CRON_EXPRESSIONS } from 'nestjs-temporal-core';
90
125
 
91
126
  @Injectable()
92
127
  export class ScheduledService {
93
- // Automatic scheduling - runs at 9 AM daily
94
- @Cron('0 9 * * *', {
95
- scheduleId: 'daily-user-report',
96
- description: 'Generate daily user report'
128
+
129
+ @Scheduled({
130
+ scheduleId: 'daily-report',
131
+ cron: CRON_EXPRESSIONS.DAILY_8AM,
132
+ description: 'Generate daily sales report',
133
+ taskQueue: 'reports'
97
134
  })
98
135
  async generateDailyReport(): Promise<void> {
99
- console.log('Generating daily user report...');
100
- // Report generation logic
136
+ console.log('Generating daily report...');
137
+ // Your report generation logic
138
+ }
139
+
140
+ @Cron(CRON_EXPRESSIONS.WEEKLY_MONDAY_9AM, {
141
+ scheduleId: 'weekly-cleanup'
142
+ })
143
+ async performWeeklyCleanup(): Promise<void> {
144
+ console.log('Performing weekly cleanup...');
145
+ // Your cleanup logic
101
146
  }
102
147
 
103
- // Interval-based scheduling - runs every hour
104
- @Interval('1h', {
105
- scheduleId: 'hourly-cleanup',
106
- description: 'Hourly cleanup task'
148
+ @Interval('5m', {
149
+ scheduleId: 'health-check'
107
150
  })
108
- async cleanupTask(): Promise<void> {
109
- console.log('Running cleanup task...');
110
- // Cleanup logic
151
+ async performHealthCheck(): Promise<void> {
152
+ console.log('Performing health check...');
153
+ // Your health check logic
111
154
  }
112
155
  }
113
156
  ```
114
157
 
115
- ### 4. Use in Services
158
+ ### 5. Use in Services
116
159
 
117
160
  ```typescript
118
- // services/user.service.ts
161
+ // services/order.service.ts
119
162
  import { Injectable } from '@nestjs/common';
120
163
  import { TemporalService } from 'nestjs-temporal-core';
121
164
 
122
165
  @Injectable()
123
- export class UserService {
166
+ export class OrderService {
124
167
  constructor(private readonly temporal: TemporalService) {}
125
168
 
126
- async processUser(email: string, name: string): Promise<string> {
127
- // Start workflow directly with client
169
+ async createOrder(orderData: any) {
128
170
  const { workflowId } = await this.temporal.startWorkflow(
129
- 'processUser',
130
- [email, name],
131
- {
132
- taskQueue: 'user-processing',
133
- workflowId: `user-${email}-${Date.now()}`
171
+ 'processOrder',
172
+ [orderData],
173
+ {
174
+ taskQueue: 'orders',
175
+ workflowId: `order-${orderData.id}`,
176
+ searchAttributes: {
177
+ 'customer-id': orderData.customerId
178
+ }
134
179
  }
135
180
  );
136
181
 
137
- return workflowId;
138
- }
139
-
140
- async getUserStatus(workflowId: string): Promise<string> {
141
- return await this.temporal.queryWorkflow(workflowId, 'getStatus');
142
- }
143
-
144
- async updateUserStatus(workflowId: string, status: string): Promise<void> {
145
- await this.temporal.signalWorkflow(workflowId, 'updateStatus', [status]);
182
+ return { workflowId };
146
183
  }
147
184
 
148
- // Schedule management
149
- async pauseDailyReport(): Promise<void> {
150
- await this.temporal.pauseSchedule('daily-user-report', 'Maintenance mode');
185
+ async cancelOrder(orderId: string) {
186
+ await this.temporal.signalWorkflow(`order-${orderId}`, 'cancel');
187
+ return { cancelled: true };
151
188
  }
152
189
 
153
- async resumeDailyReport(): Promise<void> {
154
- await this.temporal.resumeSchedule('daily-user-report');
190
+ async getOrderStatus(orderId: string) {
191
+ const status = await this.temporal.queryWorkflow(`order-${orderId}`, 'getStatus');
192
+ return status;
155
193
  }
156
194
  }
157
195
  ```
158
196
 
159
- ## ⚙️ Configuration Options
197
+ ## 🏗️ Integration Patterns
160
198
 
161
- ### Basic Configuration
162
-
163
- ```typescript
164
- TemporalModule.register({
165
- connection: {
166
- address: 'localhost:7233',
167
- namespace: 'default',
168
- },
169
- taskQueue: 'my-app',
170
- worker: {
171
- workflowsPath: './dist/workflows',
172
- activityClasses: [EmailActivities, PaymentActivities],
173
- },
174
- });
175
- ```
199
+ ### Client-Only Integration
176
200
 
177
- ### Client-Only Mode
201
+ For applications that only start workflows (e.g., web APIs):
178
202
 
179
203
  ```typescript
180
- TemporalModule.forClient({
181
- connection: {
182
- address: 'temporal.company.com:7233',
183
- namespace: 'production',
184
- tls: true,
185
- },
186
- });
204
+ import { TemporalClientModule } from 'nestjs-temporal-core';
205
+
206
+ @Module({
207
+ imports: [
208
+ TemporalClientModule.forRoot({
209
+ connection: {
210
+ address: 'localhost:7233',
211
+ namespace: 'production'
212
+ }
213
+ })
214
+ ],
215
+ providers: [ApiService],
216
+ })
217
+ export class ClientOnlyModule {}
187
218
  ```
188
219
 
189
- ### Worker-Only Mode
220
+ ### Worker-Only Integration
221
+
222
+ For dedicated worker processes:
190
223
 
191
224
  ```typescript
192
- TemporalModule.forWorker({
193
- connection: {
194
- address: 'localhost:7233',
195
- namespace: 'development',
196
- },
197
- taskQueue: 'worker-queue',
198
- workflowsPath: './dist/workflows',
199
- activityClasses: [ProcessingActivities],
200
- });
225
+ import { TemporalWorkerModule, WORKER_PRESETS } from 'nestjs-temporal-core';
226
+
227
+ @Module({
228
+ imports: [
229
+ TemporalWorkerModule.forRoot({
230
+ connection: {
231
+ address: 'localhost:7233',
232
+ namespace: 'production'
233
+ },
234
+ taskQueue: 'worker-queue',
235
+ workflowsPath: './dist/workflows',
236
+ activityClasses: [ProcessingActivities],
237
+ workerOptions: WORKER_PRESETS.PRODUCTION_HIGH_THROUGHPUT
238
+ })
239
+ ],
240
+ providers: [ProcessingActivities],
241
+ })
242
+ export class WorkerOnlyModule {}
201
243
  ```
202
244
 
203
- ### Async Configuration
245
+ ### Modular Integration
246
+
247
+ Using individual modules for specific needs:
204
248
 
205
249
  ```typescript
206
- TemporalModule.registerAsync({
207
- imports: [ConfigModule],
208
- useFactory: (config: ConfigService) => ({
209
- connection: {
210
- address: config.get('TEMPORAL_ADDRESS'),
211
- namespace: config.get('TEMPORAL_NAMESPACE'),
212
- },
213
- taskQueue: config.get('TEMPORAL_TASK_QUEUE'),
214
- worker: {
215
- workflowsPath: './dist/workflows',
216
- activityClasses: [EmailActivities],
217
- },
218
- }),
219
- inject: [ConfigService],
220
- });
250
+ import {
251
+ TemporalClientModule,
252
+ TemporalActivityModule,
253
+ TemporalSchedulesModule
254
+ } from 'nestjs-temporal-core';
255
+
256
+ @Module({
257
+ imports: [
258
+ // Client for workflow operations
259
+ TemporalClientModule.forRoot({
260
+ connection: { address: 'localhost:7233' }
261
+ }),
262
+
263
+ // Activities management
264
+ TemporalActivityModule.forRoot({
265
+ activityClasses: [EmailActivities, PaymentActivities]
266
+ }),
267
+
268
+ // Schedule management
269
+ TemporalSchedulesModule.forRoot({
270
+ autoStart: true,
271
+ defaultTimezone: 'UTC'
272
+ }),
273
+ ],
274
+ providers: [EmailActivities, PaymentActivities, ScheduledService],
275
+ })
276
+ export class ModularIntegrationModule {}
221
277
  ```
222
278
 
223
- ## 📋 Core Concepts
279
+ ## ⚙️ Configuration
224
280
 
225
- ### Auto-Discovery
226
- The module automatically discovers and registers:
227
- - **Activity Classes** marked with `@Activity`
228
- - **Scheduled Workflows** marked with `@Cron` or `@Interval`
229
- - **Signals and Queries** within classes
281
+ ### Async Configuration
230
282
 
231
- ### Scheduling Made Simple
232
283
  ```typescript
233
- // Just add the decorator - schedule is created automatically!
234
- @Cron('0 8 * * *', { scheduleId: 'daily-report' })
235
- async generateReport(): Promise<void> {
236
- // This will run every day at 8 AM
237
- }
284
+ import { ConfigModule, ConfigService } from '@nestjs/config';
285
+
286
+ @Module({
287
+ imports: [
288
+ ConfigModule.forRoot(),
289
+ TemporalModule.registerAsync({
290
+ imports: [ConfigModule],
291
+ useFactory: async (config: ConfigService) => ({
292
+ connection: {
293
+ address: config.get('TEMPORAL_ADDRESS'),
294
+ namespace: config.get('TEMPORAL_NAMESPACE'),
295
+ tls: config.get('TEMPORAL_TLS_ENABLED') === 'true',
296
+ apiKey: config.get('TEMPORAL_API_KEY'),
297
+ },
298
+ taskQueue: config.get('TEMPORAL_TASK_QUEUE'),
299
+ worker: {
300
+ workflowsPath: config.get('WORKFLOWS_PATH'),
301
+ activityClasses: [EmailActivities, PaymentActivities],
302
+ autoStart: config.get('WORKER_AUTO_START') !== 'false',
303
+ }
304
+ }),
305
+ inject: [ConfigService],
306
+ })
307
+ ],
308
+ })
309
+ export class AppModule {}
238
310
  ```
239
311
 
240
- ## 🔧 Common Use Cases
312
+ ### Environment-Specific Configurations
241
313
 
242
- ### Scheduled Reports
243
314
  ```typescript
244
- @Injectable()
245
- export class ReportService {
246
- @Cron('0 0 * * 0', { scheduleId: 'weekly-sales-report' })
247
- async generateWeeklySalesReport(): Promise<void> {
248
- // Automatically runs every Sunday at midnight
249
- console.log('Generating weekly sales report...');
315
+ // Development
316
+ const developmentConfig = {
317
+ connection: {
318
+ address: 'localhost:7233',
319
+ namespace: 'development'
320
+ },
321
+ taskQueue: 'dev-queue',
322
+ worker: {
323
+ workflowsPath: './dist/workflows',
324
+ workerOptions: WORKER_PRESETS.DEVELOPMENT
250
325
  }
251
- }
326
+ };
327
+
328
+ // Production
329
+ const productionConfig = {
330
+ connection: {
331
+ address: process.env.TEMPORAL_ADDRESS!,
332
+ namespace: process.env.TEMPORAL_NAMESPACE!,
333
+ tls: true,
334
+ apiKey: process.env.TEMPORAL_API_KEY
335
+ },
336
+ taskQueue: process.env.TEMPORAL_TASK_QUEUE!,
337
+ worker: {
338
+ workflowBundle: require('../workflows/bundle'), // Pre-bundled
339
+ workerOptions: WORKER_PRESETS.PRODUCTION_BALANCED
340
+ }
341
+ };
252
342
  ```
253
343
 
254
- ### Data Processing
344
+ ## 📊 Health Monitoring
345
+
346
+ Built-in health monitoring for production environments:
347
+
255
348
  ```typescript
256
- @Injectable()
257
- @Activity()
258
- export class DataProcessingActivities {
259
- @ActivityMethod()
260
- async processFile(filePath: string): Promise<string> {
261
- console.log(`Processing file: ${filePath}`);
262
- // File processing logic
263
- return 'processed';
349
+ @Controller('health')
350
+ export class HealthController {
351
+ constructor(private readonly temporal: TemporalService) {}
352
+
353
+ @Get('temporal')
354
+ async getTemporalHealth() {
355
+ const health = await this.temporal.getOverallHealth();
356
+ return {
357
+ status: health.status,
358
+ components: health.components,
359
+ timestamp: new Date().toISOString()
360
+ };
264
361
  }
265
362
 
266
- @ActivityMethod()
267
- async sendNotification(message: string): Promise<void> {
268
- console.log(`Sending notification: ${message}`);
269
- // Notification logic
363
+ @Get('temporal/detailed')
364
+ async getDetailedStatus() {
365
+ const systemStatus = await this.temporal.getSystemStatus();
366
+ const stats = this.temporal.getDiscoveryStats();
367
+
368
+ return {
369
+ system: systemStatus,
370
+ discovery: stats,
371
+ schedules: this.temporal.getScheduleStats()
372
+ };
270
373
  }
271
374
  }
272
375
  ```
273
376
 
274
- ### Monitoring Tasks
377
+ ## 🔧 Advanced Features
378
+
379
+ ### Activity Options
380
+
275
381
  ```typescript
382
+ @Activity()
276
383
  @Injectable()
277
- export class MonitoringService {
278
- @Interval('5m', {
279
- scheduleId: 'health-check',
280
- description: 'Health check every 5 minutes'
384
+ export class PaymentActivities {
385
+
386
+ @ActivityMethod({
387
+ name: 'processPayment',
388
+ timeout: '2m',
389
+ maxRetries: 5,
390
+ retryPolicy: {
391
+ maximumAttempts: 5,
392
+ initialInterval: '1s',
393
+ maximumInterval: '60s',
394
+ backoffCoefficient: 2.0
395
+ }
281
396
  })
282
- async healthCheck(): Promise<void> {
283
- console.log('Running health check...');
284
- // Health check logic
397
+ async processPayment(orderId: string, amount: number) {
398
+ // Complex payment processing with retries
285
399
  }
286
400
  }
287
401
  ```
288
402
 
289
- ## 📊 Monitoring & Health Checks
403
+ ### Schedule Management
290
404
 
291
405
  ```typescript
292
406
  @Injectable()
293
- export class MonitoringService {
407
+ export class ScheduleManagementService {
294
408
  constructor(private readonly temporal: TemporalService) {}
295
409
 
296
- async getSystemHealth() {
297
- // Comprehensive health status
298
- const health = await this.temporal.getOverallHealth();
299
- return {
300
- status: health.status, // 'healthy' | 'degraded' | 'unhealthy'
301
- components: health.components,
302
- };
410
+ async pauseSchedule(scheduleId: string) {
411
+ await this.temporal.pauseSchedule(scheduleId, 'Maintenance mode');
303
412
  }
304
413
 
305
- async getDiscoveryInfo() {
306
- // What was discovered
307
- const schedules = this.temporal.getManagedSchedules();
308
- const stats = this.temporal.getDiscoveryStats();
309
-
310
- return { schedules, stats };
414
+ async resumeSchedule(scheduleId: string) {
415
+ await this.temporal.resumeSchedule(scheduleId);
311
416
  }
312
417
 
313
- async manageSchedules() {
314
- // Schedule management
315
- await this.temporal.pauseSchedule('daily-report', 'Maintenance');
316
- await this.temporal.resumeSchedule('daily-report');
317
- await this.temporal.triggerSchedule('daily-report'); // Run now
418
+ async triggerScheduleNow(scheduleId: string) {
419
+ await this.temporal.triggerSchedule(scheduleId);
318
420
  }
421
+
422
+ async getScheduleInfo(scheduleId: string) {
423
+ return this.temporal.getScheduleInfo(scheduleId);
424
+ }
425
+ }
426
+ ```
427
+
428
+ ### Workflow Signals and Queries
429
+
430
+ ```typescript
431
+ // In your workflow
432
+ import { defineSignal, defineQuery, setHandler } from '@temporalio/workflow';
433
+
434
+ export const cancelSignal = defineSignal('cancel');
435
+ export const getStatusQuery = defineQuery<string>('getStatus');
436
+
437
+ export async function orderWorkflow(orderData: any) {
438
+ let status = 'processing';
439
+ let cancelled = false;
440
+
441
+ // Handle cancel signal
442
+ setHandler(cancelSignal, () => {
443
+ cancelled = true;
444
+ status = 'cancelled';
445
+ });
446
+
447
+ // Handle status query
448
+ setHandler(getStatusQuery, () => status);
449
+
450
+ // Workflow logic with cancellation support
451
+ if (cancelled) return;
452
+
453
+ // Process order...
454
+ status = 'completed';
319
455
  }
320
456
  ```
321
457
 
322
- ## 🌟 Why This Package?
458
+ ## 🌐 Temporal Cloud Integration
323
459
 
324
- - **🎯 NestJS First** - Built specifically for NestJS with familiar patterns
325
- - **🔄 Auto-Discovery** - No manual registration, just use decorators
326
- - **📅 Built-in Scheduling** - Cron jobs that integrate with workflows
327
- - **🔧 Production Ready** - Health checks, monitoring, graceful shutdowns
328
- - **📚 Easy to Learn** - Familiar NestJS service patterns
329
- - **🚀 Scalable** - Client-only, worker-only, or unified deployments
460
+ For Temporal Cloud deployments:
461
+
462
+ ```typescript
463
+ TemporalModule.register({
464
+ connection: {
465
+ address: 'your-namespace.account.tmprl.cloud:7233',
466
+ namespace: 'your-namespace.account',
467
+ tls: true,
468
+ apiKey: process.env.TEMPORAL_API_KEY,
469
+ metadata: {
470
+ 'temporal-namespace': 'your-namespace.account'
471
+ }
472
+ },
473
+ taskQueue: 'production-queue',
474
+ worker: {
475
+ workflowBundle: require('../workflows/bundle'),
476
+ workerOptions: WORKER_PRESETS.PRODUCTION_BALANCED
477
+ }
478
+ })
479
+ ```
480
+
481
+ ## 📋 Best Practices
482
+
483
+ ### 1. **Activity Design**
484
+ - Keep activities idempotent
485
+ - Use proper timeouts and retry policies
486
+ - Handle errors gracefully
487
+ - Use dependency injection for testability
488
+
489
+ ### 2. **Workflow Organization**
490
+ - Separate workflow files from activities
491
+ - Use TypeScript for type safety
492
+ - Keep workflows deterministic
493
+ - Bundle workflows for production
494
+
495
+ ### 3. **Configuration Management**
496
+ - Use environment variables for connection settings
497
+ - Separate configs for different environments
498
+ - Use async configuration for dynamic settings
499
+ - Validate configuration at startup
500
+
501
+ ### 4. **Monitoring & Observability**
502
+ - Implement health checks
503
+ - Monitor worker status
504
+ - Track schedule execution
505
+ - Use structured logging
506
+
507
+ ### 5. **Production Deployment**
508
+ - Use pre-bundled workflows
509
+ - Configure appropriate worker limits
510
+ - Enable TLS for security
511
+ - Implement graceful shutdowns
512
+
513
+ ## 📚 API Reference
514
+
515
+ ### Decorators
516
+
517
+ - `@Activity()` - Mark a class as containing activities
518
+ - `@ActivityMethod(options?)` - Define an activity method
519
+ - `@Scheduled(options)` - Schedule a workflow with full options
520
+ - `@Cron(expression, options?)` - Schedule using cron expression
521
+ - `@Interval(interval, options?)` - Schedule using interval
522
+
523
+ ### Services
524
+
525
+ - `TemporalService` - Main service for all operations
526
+ - `TemporalClientService` - Client-only operations
527
+ - `TemporalActivityService` - Activity management
528
+ - `TemporalSchedulesService` - Schedule management
529
+ - `TemporalWorkerManagerService` - Worker lifecycle
530
+
531
+ ### Constants
532
+
533
+ - `CRON_EXPRESSIONS` - Common cron patterns
534
+ - `INTERVAL_EXPRESSIONS` - Common interval patterns
535
+ - `WORKER_PRESETS` - Environment-specific worker configs
536
+ - `RETRY_POLICIES` - Common retry patterns
537
+ - `TIMEOUTS` - Common timeout values
330
538
 
331
539
  ## 🤝 Contributing
332
540
 
333
- Contributions welcome! Please read our [Contributing Guide](./CONTRIBUTING.md) for details.
541
+ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
334
542
 
335
543
  ## 📄 License
336
544
 
337
- MIT License - see [LICENSE](LICENSE) file for details.
545
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
546
+
547
+ ## 🙏 Acknowledgments
548
+
549
+ - [Temporal.io](https://temporal.io/) for the amazing workflow engine
550
+ - [NestJS](https://nestjs.com/) for the fantastic framework
551
+ - The TypeScript community for excellent tooling
552
+
553
+ ---
554
+
555
+ Built with ❤️ for the NestJS and Temporal communities