@ooneex/cron 0.0.1 → 0.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 +549 -0
- package/dist/index.d.ts +26 -12
- package/dist/index.js +2 -2
- package/dist/index.js.map +7 -4
- package/package.json +19 -8
- package/dist/ooneex-cron-0.0.1.tgz +0 -0
package/README.md
CHANGED
|
@@ -1 +1,550 @@
|
|
|
1
1
|
# @ooneex/cron
|
|
2
|
+
|
|
3
|
+
A scheduled task runner and cron job management library for TypeScript applications with timezone support. This package provides an abstract base class for creating scheduled jobs with a human-readable time syntax and seamless integration with the Ooneex framework.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
✅ **Human-Readable Syntax** - Define schedules with intuitive syntax like "every 1 hours"
|
|
14
|
+
|
|
15
|
+
✅ **Timezone Support** - Run jobs in specific timezones using IANA timezone names
|
|
16
|
+
|
|
17
|
+
✅ **Start/Stop Control** - Programmatically start and stop scheduled jobs
|
|
18
|
+
|
|
19
|
+
✅ **Active Status** - Check if a job is currently running
|
|
20
|
+
|
|
21
|
+
✅ **Container Integration** - Works seamlessly with dependency injection
|
|
22
|
+
|
|
23
|
+
✅ **Type-Safe** - Full TypeScript support with proper type definitions
|
|
24
|
+
|
|
25
|
+
✅ **Error Handling** - Comprehensive error handling with custom exceptions
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
### Bun
|
|
30
|
+
```bash
|
|
31
|
+
bun add @ooneex/cron
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### pnpm
|
|
35
|
+
```bash
|
|
36
|
+
pnpm add @ooneex/cron
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Yarn
|
|
40
|
+
```bash
|
|
41
|
+
yarn add @ooneex/cron
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### npm
|
|
45
|
+
```bash
|
|
46
|
+
npm install @ooneex/cron
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
### Basic Cron Job
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { Cron, type CronTimeType } from '@ooneex/cron';
|
|
55
|
+
import type { TimeZoneType } from '@ooneex/country';
|
|
56
|
+
|
|
57
|
+
class CleanupCron extends Cron {
|
|
58
|
+
public getTime(): CronTimeType {
|
|
59
|
+
return 'every 1 hours';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public getTimeZone(): TimeZoneType | null {
|
|
63
|
+
return null; // Use server's local timezone
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public async job(): Promise<void> {
|
|
67
|
+
console.log('Running cleanup task...');
|
|
68
|
+
// Cleanup logic here
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Start the cron job
|
|
73
|
+
const cleanup = new CleanupCron();
|
|
74
|
+
await cleanup.start();
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### With Timezone Support
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { Cron, type CronTimeType } from '@ooneex/cron';
|
|
81
|
+
import type { TimeZoneType } from '@ooneex/country';
|
|
82
|
+
|
|
83
|
+
class DailyReportCron extends Cron {
|
|
84
|
+
public getTime(): CronTimeType {
|
|
85
|
+
return 'every 24 hours';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public getTimeZone(): TimeZoneType | null {
|
|
89
|
+
return 'Europe/Paris'; // Run at Paris time
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public async job(): Promise<void> {
|
|
93
|
+
await this.generateDailyReport();
|
|
94
|
+
await this.sendReportEmail();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private async generateDailyReport(): Promise<void> {
|
|
98
|
+
// Report generation logic
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private async sendReportEmail(): Promise<void> {
|
|
102
|
+
// Email sending logic
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Different Time Intervals
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { Cron, type CronTimeType } from '@ooneex/cron';
|
|
111
|
+
|
|
112
|
+
// Every 30 seconds
|
|
113
|
+
class FrequentCheckCron extends Cron {
|
|
114
|
+
public getTime(): CronTimeType {
|
|
115
|
+
return 'every 30 seconds';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public getTimeZone(): null {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public async job(): Promise<void> {
|
|
123
|
+
console.log('Checking...');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Every 5 minutes
|
|
128
|
+
class CacheRefreshCron extends Cron {
|
|
129
|
+
public getTime(): CronTimeType {
|
|
130
|
+
return 'every 5 minutes';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public getTimeZone(): null {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public async job(): Promise<void> {
|
|
138
|
+
await this.refreshCache();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Every 7 days (weekly)
|
|
143
|
+
class WeeklyBackupCron extends Cron {
|
|
144
|
+
public getTime(): CronTimeType {
|
|
145
|
+
return 'every 7 days';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public getTimeZone(): TimeZoneType | null {
|
|
149
|
+
return 'America/New_York';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public async job(): Promise<void> {
|
|
153
|
+
await this.performBackup();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Controlling Cron Jobs
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { Cron } from '@ooneex/cron';
|
|
162
|
+
|
|
163
|
+
const job = new MyCronJob();
|
|
164
|
+
|
|
165
|
+
// Start the job
|
|
166
|
+
await job.start();
|
|
167
|
+
console.log('Job is active:', job.isActive()); // true
|
|
168
|
+
|
|
169
|
+
// Stop the job
|
|
170
|
+
await job.stop();
|
|
171
|
+
console.log('Job is active:', job.isActive()); // false
|
|
172
|
+
|
|
173
|
+
// Restart the job
|
|
174
|
+
await job.start();
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## API Reference
|
|
178
|
+
|
|
179
|
+
### Classes
|
|
180
|
+
|
|
181
|
+
#### `Cron` (Abstract)
|
|
182
|
+
|
|
183
|
+
Abstract base class for creating scheduled jobs.
|
|
184
|
+
|
|
185
|
+
**Abstract Methods to Implement:**
|
|
186
|
+
|
|
187
|
+
##### `getTime(): CronTimeType`
|
|
188
|
+
|
|
189
|
+
Returns the schedule timing for the job.
|
|
190
|
+
|
|
191
|
+
**Returns:** A string in the format `"every N units"` or `"in N units"`
|
|
192
|
+
|
|
193
|
+
**Example:**
|
|
194
|
+
```typescript
|
|
195
|
+
public getTime(): CronTimeType {
|
|
196
|
+
return 'every 1 hours';
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
##### `getTimeZone(): TimeZoneType | null`
|
|
201
|
+
|
|
202
|
+
Returns the timezone for the job schedule.
|
|
203
|
+
|
|
204
|
+
**Returns:** IANA timezone string or `null` for server's local timezone
|
|
205
|
+
|
|
206
|
+
**Example:**
|
|
207
|
+
```typescript
|
|
208
|
+
public getTimeZone(): TimeZoneType | null {
|
|
209
|
+
return 'Europe/London';
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
##### `job(): Promise<void>`
|
|
214
|
+
|
|
215
|
+
The task to execute on schedule.
|
|
216
|
+
|
|
217
|
+
**Example:**
|
|
218
|
+
```typescript
|
|
219
|
+
public async job(): Promise<void> {
|
|
220
|
+
await this.performTask();
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Inherited Methods:**
|
|
225
|
+
|
|
226
|
+
##### `start(): Promise<void>`
|
|
227
|
+
|
|
228
|
+
Starts the cron job. If already active, does nothing.
|
|
229
|
+
|
|
230
|
+
**Throws:** `CronException` if the job fails to start
|
|
231
|
+
|
|
232
|
+
**Example:**
|
|
233
|
+
```typescript
|
|
234
|
+
const job = new MyCronJob();
|
|
235
|
+
await job.start();
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
##### `stop(): Promise<void>`
|
|
239
|
+
|
|
240
|
+
Stops the cron job.
|
|
241
|
+
|
|
242
|
+
**Example:**
|
|
243
|
+
```typescript
|
|
244
|
+
await job.stop();
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
##### `isActive(): boolean`
|
|
248
|
+
|
|
249
|
+
Checks if the cron job is currently running.
|
|
250
|
+
|
|
251
|
+
**Returns:** `true` if the job is active, `false` otherwise
|
|
252
|
+
|
|
253
|
+
**Example:**
|
|
254
|
+
```typescript
|
|
255
|
+
if (job.isActive()) {
|
|
256
|
+
console.log('Job is running');
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Types
|
|
261
|
+
|
|
262
|
+
#### `CronTimeType`
|
|
263
|
+
|
|
264
|
+
String format for defining job schedules.
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
type CronTimeType = `${PrefixType} ${number} ${SuffixType}`;
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Examples:**
|
|
271
|
+
- `'every 1 seconds'`
|
|
272
|
+
- `'every 30 seconds'`
|
|
273
|
+
- `'every 5 minutes'`
|
|
274
|
+
- `'every 1 hours'`
|
|
275
|
+
- `'every 24 hours'`
|
|
276
|
+
- `'every 7 days'`
|
|
277
|
+
- `'every 1 months'`
|
|
278
|
+
- `'every 1 years'`
|
|
279
|
+
- `'in 10 seconds'`
|
|
280
|
+
- `'in 5 minutes'`
|
|
281
|
+
|
|
282
|
+
#### `PrefixType`
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
type PrefixType = 'in' | 'every';
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
#### `SuffixType`
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
type SuffixType = 'seconds' | 'minutes' | 'hours' | 'days' | 'months' | 'years';
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
#### `CronClassType`
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
type CronClassType = new (...args: any[]) => ICron;
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Enums
|
|
301
|
+
|
|
302
|
+
#### `ECronPrefix`
|
|
303
|
+
|
|
304
|
+
| Value | Description |
|
|
305
|
+
|-------|-------------|
|
|
306
|
+
| `IN` | Run once after specified time |
|
|
307
|
+
| `EVERY` | Run repeatedly at specified interval |
|
|
308
|
+
|
|
309
|
+
#### `ECronSuffix`
|
|
310
|
+
|
|
311
|
+
| Value | Description |
|
|
312
|
+
|-------|-------------|
|
|
313
|
+
| `SECONDS` | Time in seconds |
|
|
314
|
+
| `MINUTES` | Time in minutes |
|
|
315
|
+
| `HOURS` | Time in hours |
|
|
316
|
+
| `DAYS` | Time in days |
|
|
317
|
+
| `MONTHS` | Time in months |
|
|
318
|
+
| `YEARS` | Time in years |
|
|
319
|
+
|
|
320
|
+
### Interfaces
|
|
321
|
+
|
|
322
|
+
#### `ICron`
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
interface ICron {
|
|
326
|
+
getTime: () => Promise<CronTimeType> | CronTimeType;
|
|
327
|
+
start: () => Promise<void> | void;
|
|
328
|
+
stop: () => Promise<void> | void;
|
|
329
|
+
job: () => Promise<void> | void;
|
|
330
|
+
getTimeZone: () => TimeZoneType | null;
|
|
331
|
+
isActive: () => Promise<boolean> | boolean;
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Advanced Usage
|
|
336
|
+
|
|
337
|
+
### Integration with Ooneex App
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
import { App } from '@ooneex/app';
|
|
341
|
+
import { CleanupCron, BackupCron, ReportCron } from './cron';
|
|
342
|
+
|
|
343
|
+
const app = new App({
|
|
344
|
+
cronJobs: [CleanupCron, BackupCron, ReportCron],
|
|
345
|
+
// ... other config
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
await app.run();
|
|
349
|
+
// All cron jobs are automatically started
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Using Container Decorators
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import { Cron, decorator, type CronTimeType } from '@ooneex/cron';
|
|
356
|
+
import { container } from '@ooneex/container';
|
|
357
|
+
|
|
358
|
+
@decorator.cron()
|
|
359
|
+
class EmailQueueCron extends Cron {
|
|
360
|
+
public getTime(): CronTimeType {
|
|
361
|
+
return 'every 1 minutes';
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
public getTimeZone(): null {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
public async job(): Promise<void> {
|
|
369
|
+
await this.processEmailQueue();
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Job is automatically registered with container
|
|
374
|
+
const job = container.get(EmailQueueCron);
|
|
375
|
+
await job.start();
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Error Handling
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
import { Cron, CronException, type CronTimeType } from '@ooneex/cron';
|
|
382
|
+
|
|
383
|
+
class RiskyJob extends Cron {
|
|
384
|
+
public getTime(): CronTimeType {
|
|
385
|
+
return 'every 5 minutes';
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
public getTimeZone(): null {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
public async job(): Promise<void> {
|
|
393
|
+
try {
|
|
394
|
+
await this.riskyOperation();
|
|
395
|
+
} catch (error) {
|
|
396
|
+
console.error('Job failed:', error);
|
|
397
|
+
// Handle error without crashing the scheduler
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Handle startup errors
|
|
403
|
+
try {
|
|
404
|
+
const job = new RiskyJob();
|
|
405
|
+
await job.start();
|
|
406
|
+
} catch (error) {
|
|
407
|
+
if (error instanceof CronException) {
|
|
408
|
+
console.error('Failed to start cron job:', error.message);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Conditional Job Execution
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
import { Cron, type CronTimeType } from '@ooneex/cron';
|
|
417
|
+
|
|
418
|
+
class ConditionalCron extends Cron {
|
|
419
|
+
private enabled = true;
|
|
420
|
+
|
|
421
|
+
public getTime(): CronTimeType {
|
|
422
|
+
return 'every 1 hours';
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
public getTimeZone(): null {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
public async job(): Promise<void> {
|
|
430
|
+
if (!this.enabled) {
|
|
431
|
+
console.log('Job skipped - disabled');
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
await this.performTask();
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
public enable(): void {
|
|
439
|
+
this.enabled = true;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
public disable(): void {
|
|
443
|
+
this.enabled = false;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Job with Logging
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
import { Cron, type CronTimeType } from '@ooneex/cron';
|
|
452
|
+
import { container } from '@ooneex/container';
|
|
453
|
+
import type { ILogger } from '@ooneex/logger';
|
|
454
|
+
|
|
455
|
+
class LoggingCron extends Cron {
|
|
456
|
+
private readonly logger = container.get<ILogger>('logger');
|
|
457
|
+
|
|
458
|
+
public getTime(): CronTimeType {
|
|
459
|
+
return 'every 30 minutes';
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
public getTimeZone(): TimeZoneType | null {
|
|
463
|
+
return 'UTC';
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
public async job(): Promise<void> {
|
|
467
|
+
this.logger.info('Cron job started', { job: 'LoggingCron' });
|
|
468
|
+
|
|
469
|
+
try {
|
|
470
|
+
await this.performTask();
|
|
471
|
+
this.logger.success('Cron job completed', { job: 'LoggingCron' });
|
|
472
|
+
} catch (error) {
|
|
473
|
+
this.logger.error('Cron job failed', {
|
|
474
|
+
job: 'LoggingCron',
|
|
475
|
+
error: error instanceof Error ? error.message : String(error)
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### Multiple Jobs with Shared Resources
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
import { Cron, type CronTimeType } from '@ooneex/cron';
|
|
486
|
+
import { container } from '@ooneex/container';
|
|
487
|
+
import type { ICache } from '@ooneex/cache';
|
|
488
|
+
import type { IDatabase } from '@ooneex/database';
|
|
489
|
+
|
|
490
|
+
abstract class BaseCron extends Cron {
|
|
491
|
+
protected readonly cache = container.get<ICache>('cache');
|
|
492
|
+
protected readonly database = container.get<IDatabase>('database');
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
class CacheWarmupCron extends BaseCron {
|
|
496
|
+
public getTime(): CronTimeType {
|
|
497
|
+
return 'every 15 minutes';
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
public getTimeZone(): null {
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
public async job(): Promise<void> {
|
|
505
|
+
const data = await this.database.query('SELECT * FROM hot_data');
|
|
506
|
+
await this.cache.set('hot_data', data, 900); // 15 min TTL
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
class DataCleanupCron extends BaseCron {
|
|
511
|
+
public getTime(): CronTimeType {
|
|
512
|
+
return 'every 1 days';
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
public getTimeZone(): TimeZoneType | null {
|
|
516
|
+
return 'UTC';
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
public async job(): Promise<void> {
|
|
520
|
+
await this.database.query('DELETE FROM logs WHERE created_at < NOW() - INTERVAL 30 DAY');
|
|
521
|
+
await this.cache.delete('old_cache_key');
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## License
|
|
527
|
+
|
|
528
|
+
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
|
|
529
|
+
|
|
530
|
+
## Contributing
|
|
531
|
+
|
|
532
|
+
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
|
|
533
|
+
|
|
534
|
+
### Development Setup
|
|
535
|
+
|
|
536
|
+
1. Clone the repository
|
|
537
|
+
2. Install dependencies: `bun install`
|
|
538
|
+
3. Run tests: `bun run test`
|
|
539
|
+
4. Build the project: `bun run build`
|
|
540
|
+
|
|
541
|
+
### Guidelines
|
|
542
|
+
|
|
543
|
+
- Write tests for new features
|
|
544
|
+
- Follow the existing code style
|
|
545
|
+
- Update documentation for API changes
|
|
546
|
+
- Ensure all tests pass before submitting PR
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
Made with ❤️ by the Ooneex team
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
constructor(message: string, data?: Record<string, unknown>);
|
|
4
|
-
}
|
|
1
|
+
import { TimeZoneType as TimeZoneType2 } from "@ooneex/country";
|
|
2
|
+
import { TimeZoneType } from "@ooneex/country";
|
|
5
3
|
declare enum ECronPrefix {
|
|
6
4
|
IN = "in",
|
|
7
5
|
EVERY = "every"
|
|
@@ -19,12 +17,28 @@ type SuffixType = `${ECronSuffix}`;
|
|
|
19
17
|
type CronTimeType = `${PrefixType} ${number} ${SuffixType}`;
|
|
20
18
|
type CronClassType = new (...args: any[]) => ICron;
|
|
21
19
|
interface ICron {
|
|
22
|
-
getTime: () => CronTimeType;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
getTime: () => Promise<CronTimeType> | CronTimeType;
|
|
21
|
+
start: () => Promise<void> | void;
|
|
22
|
+
stop: () => Promise<void> | void;
|
|
23
|
+
job: () => Promise<void> | void;
|
|
24
|
+
getTimeZone: () => TimeZoneType | null;
|
|
25
|
+
isActive: () => Promise<boolean> | boolean;
|
|
26
|
+
}
|
|
27
|
+
declare abstract class Cron implements ICron {
|
|
28
|
+
private cronJob;
|
|
29
|
+
abstract getTime(): CronTimeType;
|
|
30
|
+
abstract job(): Promise<void>;
|
|
31
|
+
abstract getTimeZone(): TimeZoneType2 | null;
|
|
32
|
+
start(): Promise<void>;
|
|
33
|
+
stop(): Promise<void>;
|
|
34
|
+
isActive(): boolean;
|
|
35
|
+
}
|
|
36
|
+
import { Exception } from "@ooneex/exception";
|
|
37
|
+
declare class CronException extends Exception {
|
|
38
|
+
constructor(message: string, data?: Record<string, unknown>);
|
|
29
39
|
}
|
|
30
|
-
|
|
40
|
+
import { EContainerScope } from "@ooneex/container";
|
|
41
|
+
declare const decorator: {
|
|
42
|
+
cron: (scope?: EContainerScope) => (target: CronClassType) => void;
|
|
43
|
+
};
|
|
44
|
+
export { decorator, SuffixType, PrefixType, ICron, ECronSuffix, ECronPrefix, CronTimeType, CronException, CronClassType, Cron };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{Exception as
|
|
2
|
+
import{CronJob as g}from"cron";import{Exception as T}from"@ooneex/exception";import{HttpStatus as e}from"@ooneex/http-status";class n extends T{constructor(r,i={}){super(r,{status:e.Code.InternalServerError,data:i});this.name="CronException"}}var s=(r)=>{let i=r.split(" ");if(i.length!==3)throw new n(`Invalid CronTimeType format: ${r}`);let m=i[0],t=Number.parseInt(i[1]||"1",10),p=i[2];if(Number.isNaN(t)||t<=0)throw new n(`Invalid number value in CronTimeType: ${i[1]}`);if(m==="in"){let c=new Date;switch(p){case"seconds":{let o=new Date(c.getTime()+t*1000);return`${o.getMinutes()} ${o.getHours()} ${o.getDate()} ${o.getMonth()+1} *`}case"minutes":{let o=new Date(c.getTime()+t*60*1000);return`${o.getMinutes()} ${o.getHours()} ${o.getDate()} ${o.getMonth()+1} *`}case"hours":{let o=new Date(c.getTime()+t*60*60*1000);return`${o.getMinutes()} ${o.getHours()} ${o.getDate()} ${o.getMonth()+1} *`}case"days":{let o=new Date(c.getTime()+t*24*60*60*1000);return`${o.getMinutes()} ${o.getHours()} ${o.getDate()} ${o.getMonth()+1} *`}case"months":{let o=new Date(c);return o.setMonth(o.getMonth()+t),`${o.getMinutes()} ${o.getHours()} ${o.getDate()} ${o.getMonth()+1} *`}case"years":{let o=new Date(c);return o.setFullYear(o.getFullYear()+t),`${o.getMinutes()} ${o.getHours()} ${o.getDate()} ${o.getMonth()+1} *`}}}if(m==="every")switch(p){case"seconds":if(t===1)return"* * * * * *";return`*/${t} * * * * *`;case"minutes":if(t===1)return"* * * * *";return`*/${t} * * * *`;case"hours":if(t===1)return"0 * * * *";return`0 */${t} * * *`;case"days":if(t===1)return"0 0 * * *";return`0 0 */${t} * *`;case"months":if(t===1)return"0 0 1 * *";return`0 0 1 */${t} *`;case"years":if(t===1)return"0 0 1 1 *";return"0 0 1 1 *"}throw new n(`Invalid CronTimeType format: ${r}`)};class b{cronJob=null;async start(){if(this.isActive())return;if(this.cronJob){this.cronJob.start();return}let r=s(this.getTime());try{let i={cronTime:r,onTick:async()=>{await this.job()},start:!0},m=this.getTimeZone();if(m!==null)i.timeZone=m;this.cronJob=g.from(i)}catch(i){throw new n("Failed to start cron job",{time:this.getTime(),cronExpression:r,error:i instanceof Error?i.message:String(i)})}}async stop(){if(this.cronJob)this.cronJob.stop()}isActive(){if(!this.cronJob)return!1;return this.cronJob.isActive}}import{container as y,EContainerScope as J}from"@ooneex/container";var R={cron:(r=J.Singleton)=>{return(i)=>{y.add(i,r)}}};var h;((m)=>{m.IN="in";m.EVERY="every"})(h||={});var a;((o)=>{o.SECONDS="seconds";o.MINUTES="minutes";o.HOURS="hours";o.DAYS="days";o.MONTHS="months";o.YEARS="years"})(a||={});export{R as decorator,a as ECronSuffix,h as ECronPrefix,n as CronException,b as Cron};
|
|
3
3
|
|
|
4
|
-
//# debugId=
|
|
4
|
+
//# debugId=0AE63CF58662598364756E2164756E21
|
package/dist/index.js.map
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["src/CronException.ts", "src/types.ts"],
|
|
3
|
+
"sources": ["src/Cron.ts", "src/CronException.ts", "src/helper.ts", "src/decorators.ts", "src/types.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
+
"import type { TimeZoneType } from \"@ooneex/country\";\nimport { CronJob } from \"cron\";\nimport { CronException } from \"./CronException\";\nimport { convertToCrontab } from \"./helper\";\nimport type { CronTimeType, ICron } from \"./types\";\n\nexport abstract class Cron implements ICron {\n private cronJob: CronJob | null = null;\n\n public abstract getTime(): CronTimeType;\n public abstract job(): Promise<void>;\n public abstract getTimeZone(): TimeZoneType | null;\n\n public async start(): Promise<void> {\n if (this.isActive()) {\n return;\n }\n\n if (this.cronJob) {\n this.cronJob.start();\n return;\n }\n\n const cronExpression = convertToCrontab(this.getTime());\n\n try {\n const cronParams: {\n cronTime: string;\n onTick: () => Promise<void>;\n start: boolean;\n timeZone?: string;\n } = {\n cronTime: cronExpression,\n onTick: async () => {\n await this.job();\n },\n start: true,\n };\n\n const timeZone = this.getTimeZone();\n if (timeZone !== null) {\n cronParams.timeZone = timeZone;\n }\n\n this.cronJob = CronJob.from(cronParams);\n } catch (error) {\n throw new CronException(\"Failed to start cron job\", {\n time: this.getTime(),\n cronExpression,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n public async stop(): Promise<void> {\n if (this.cronJob) {\n this.cronJob.stop();\n }\n }\n\n public isActive(): boolean {\n if (!this.cronJob) {\n return false;\n }\n\n return this.cronJob.isActive;\n }\n}\n",
|
|
5
6
|
"import { Exception } from \"@ooneex/exception\";\nimport { HttpStatus } from \"@ooneex/http-status\";\n\nexport class CronException extends Exception {\n constructor(message: string, data: Record<string, unknown> = {}) {\n super(message, {\n status: HttpStatus.Code.InternalServerError,\n data,\n });\n this.name = \"CronException\";\n }\n}\n",
|
|
6
|
-
"
|
|
7
|
+
"import { CronException } from \"./CronException\";\nimport type { CronTimeType, SuffixType } from \"./types\";\n\n/**\n * Converts a CronTimeType string to a standard crontab expression\n * @param cronTime - The CronTimeType string (e.g., \"every 5 minutes\", \"in 30 seconds\")\n * @returns A crontab expression string\n */\nexport const convertToCrontab = (cronTime: CronTimeType): string => {\n const parts = cronTime.split(\" \");\n\n if (parts.length !== 3) {\n throw new CronException(`Invalid CronTimeType format: ${cronTime}`);\n }\n\n const prefix = parts[0] as \"in\" | \"every\";\n const value = Number.parseInt(parts[1] || \"1\", 10);\n const suffix = parts[2] as SuffixType;\n\n if (Number.isNaN(value) || value <= 0) {\n throw new CronException(`Invalid number value in CronTimeType: ${parts[1]}`);\n }\n\n // Handle \"in\" prefix (one-time execution)\n if (prefix === \"in\") {\n const now = new Date();\n\n switch (suffix) {\n case \"seconds\": {\n const futureSeconds = new Date(now.getTime() + value * 1000);\n return `${futureSeconds.getMinutes()} ${futureSeconds.getHours()} ${futureSeconds.getDate()} ${futureSeconds.getMonth() + 1} *`;\n }\n\n case \"minutes\": {\n const futureMinutes = new Date(now.getTime() + value * 60 * 1000);\n return `${futureMinutes.getMinutes()} ${futureMinutes.getHours()} ${futureMinutes.getDate()} ${futureMinutes.getMonth() + 1} *`;\n }\n\n case \"hours\": {\n const futureHours = new Date(now.getTime() + value * 60 * 60 * 1000);\n return `${futureHours.getMinutes()} ${futureHours.getHours()} ${futureHours.getDate()} ${futureHours.getMonth() + 1} *`;\n }\n\n case \"days\": {\n const futureDays = new Date(now.getTime() + value * 24 * 60 * 60 * 1000);\n return `${futureDays.getMinutes()} ${futureDays.getHours()} ${futureDays.getDate()} ${futureDays.getMonth() + 1} *`;\n }\n\n case \"months\": {\n const futureMonths = new Date(now);\n futureMonths.setMonth(futureMonths.getMonth() + value);\n return `${futureMonths.getMinutes()} ${futureMonths.getHours()} ${futureMonths.getDate()} ${futureMonths.getMonth() + 1} *`;\n }\n\n case \"years\": {\n const futureYears = new Date(now);\n futureYears.setFullYear(futureYears.getFullYear() + value);\n return `${futureYears.getMinutes()} ${futureYears.getHours()} ${futureYears.getDate()} ${futureYears.getMonth() + 1} *`;\n }\n }\n }\n\n // Handle \"every\" prefix (recurring execution)\n if (prefix === \"every\") {\n switch (suffix) {\n case \"seconds\":\n if (value === 1) return \"* * * * * *\";\n return `*/${value} * * * * *`;\n\n case \"minutes\":\n if (value === 1) return \"* * * * *\";\n return `*/${value} * * * *`;\n\n case \"hours\":\n if (value === 1) return \"0 * * * *\";\n return `0 */${value} * * *`;\n\n case \"days\":\n if (value === 1) return \"0 0 * * *\";\n return `0 0 */${value} * *`;\n\n case \"months\":\n if (value === 1) return \"0 0 1 * *\";\n return `0 0 1 */${value} *`;\n\n case \"years\":\n if (value === 1) return \"0 0 1 1 *\";\n return \"0 0 1 1 *\";\n }\n }\n\n throw new CronException(`Invalid CronTimeType format: ${cronTime}`);\n};\n",
|
|
8
|
+
"import { container, EContainerScope } from \"@ooneex/container\";\nimport type { CronClassType } from \"./types\";\n\nexport const decorator = {\n cron: (scope: EContainerScope = EContainerScope.Singleton) => {\n return (target: CronClassType): void => {\n container.add(target, scope);\n };\n },\n};\n",
|
|
9
|
+
"import type { TimeZoneType } from \"@ooneex/country\";\n\nexport enum ECronPrefix {\n IN = \"in\",\n EVERY = \"every\",\n}\n\nexport enum ECronSuffix {\n SECONDS = \"seconds\",\n MINUTES = \"minutes\",\n HOURS = \"hours\",\n DAYS = \"days\",\n MONTHS = \"months\",\n YEARS = \"years\",\n}\n\nexport type PrefixType = `${ECronPrefix}`;\nexport type SuffixType = `${ECronSuffix}`;\nexport type CronTimeType = `${PrefixType} ${number} ${SuffixType}`;\n\n// biome-ignore lint/suspicious/noExplicitAny: trust me\nexport type CronClassType = new (...args: any[]) => ICron;\n\nexport interface ICron {\n getTime: () => Promise<CronTimeType> | CronTimeType;\n start: () => Promise<void> | void;\n stop: () => Promise<void> | void;\n job: () => Promise<void> | void;\n getTimeZone: () => TimeZoneType | null;\n isActive: () => Promise<boolean> | boolean;\n}\n"
|
|
7
10
|
],
|
|
8
|
-
"mappings": ";
|
|
9
|
-
"debugId": "
|
|
11
|
+
"mappings": "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",
|
|
12
|
+
"debugId": "0AE63CF58662598364756E2164756E21",
|
|
10
13
|
"names": []
|
|
11
14
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ooneex/cron",
|
|
3
|
-
"description": "",
|
|
4
|
-
"version": "0.0.
|
|
3
|
+
"description": "Scheduled task runner and cron job management with timezone support for Ooneex applications",
|
|
4
|
+
"version": "0.0.5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
@@ -25,14 +25,25 @@
|
|
|
25
25
|
"test": "bun test tests",
|
|
26
26
|
"build": "bunup",
|
|
27
27
|
"lint": "tsgo --noEmit && bunx biome lint",
|
|
28
|
-
"publish
|
|
29
|
-
"publish:pack": "bun pm pack --destination ./dist",
|
|
30
|
-
"publish:dry": "bun publish --dry-run"
|
|
28
|
+
"npm:publish": "bun publish --tolerate-republish --access public"
|
|
31
29
|
},
|
|
32
30
|
"dependencies": {
|
|
31
|
+
"@ooneex/container": "0.0.2",
|
|
33
32
|
"@ooneex/exception": "0.0.1",
|
|
34
|
-
"@ooneex/http-status": "0.0.1"
|
|
33
|
+
"@ooneex/http-status": "0.0.1",
|
|
34
|
+
"cron": "^4.4.0"
|
|
35
35
|
},
|
|
36
|
-
"devDependencies": {
|
|
37
|
-
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@ooneex/country": "0.0.1"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"bun",
|
|
41
|
+
"cron",
|
|
42
|
+
"job",
|
|
43
|
+
"ooneex",
|
|
44
|
+
"scheduler",
|
|
45
|
+
"scheduling",
|
|
46
|
+
"task",
|
|
47
|
+
"typescript"
|
|
48
|
+
]
|
|
38
49
|
}
|
|
Binary file
|