@ooneex/cron 0.0.1 → 0.0.4

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
@@ -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
+ ![Bun](https://img.shields.io/badge/Bun-Compatible-orange?style=flat-square&logo=bun)
6
+ ![Deno](https://img.shields.io/badge/Deno-Compatible-blue?style=flat-square&logo=deno)
7
+ ![Node.js](https://img.shields.io/badge/Node.js-Compatible-green?style=flat-square&logo=node.js)
8
+ ![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square&logo=typescript)
9
+ ![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)
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 { Exception } from "@ooneex/exception";
2
- declare class CronException extends Exception {
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
- setTime?: (tim: CronTimeType) => ICron;
24
- start: () => Promise<void>;
25
- stop: () => Promise<void>;
26
- job: () => Promise<void>;
27
- getTimeZone: () => Promise<string | null>;
28
- isActive: () => boolean;
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
- export { SuffixType, PrefixType, ICron, ECronSuffix, ECronPrefix, CronTimeType, CronException, CronClassType };
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 s}from"@ooneex/exception";import{HttpStatus as c}from"@ooneex/http-status";class p extends s{constructor(r,o={}){super(r,{status:c.Code.InternalServerError,data:o});this.name="CronException"}}var a;((e)=>{e.IN="in";e.EVERY="every"})(a||={});var m;((t)=>{t.SECONDS="seconds";t.MINUTES="minutes";t.HOURS="hours";t.DAYS="days";t.MONTHS="months";t.YEARS="years"})(m||={});export{m as ECronSuffix,a as ECronPrefix,p as CronException};
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=7E2B5893252706C264756E2164756E21
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
- "export 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: () => CronTimeType;\n setTime?: (tim: CronTimeType) => ICron;\n start: () => Promise<void>;\n stop: () => Promise<void>;\n job: () => Promise<void>;\n getTimeZone: () => Promise<string | null>;\n isActive: () => boolean;\n}\n"
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": ";AAAA,oBAAS,0BACT,qBAAS,4BAEF,MAAM,UAAsB,CAAU,CAC3C,WAAW,CAAC,EAAiB,EAAgC,CAAC,EAAG,CAC/D,MAAM,EAAS,CACb,OAAQ,EAAW,KAAK,oBACxB,MACF,CAAC,EACD,KAAK,KAAO,gBAEhB,CCXO,IAAK,GAAL,CAAK,IAAL,CACL,KAAK,KACL,QAAQ,UAFE,QAKL,IAAK,GAAL,CAAK,IAAL,CACL,UAAU,UACV,UAAU,UACV,QAAQ,QACR,OAAO,OACP,SAAS,SACT,QAAQ,UANE",
9
- "debugId": "7E2B5893252706C264756E2164756E21",
11
+ "mappings": ";AACA,kBAAS,aCDT,oBAAS,0BACT,qBAAS,4BAEF,MAAM,UAAsB,CAAU,CAC3C,WAAW,CAAC,EAAiB,EAAgC,CAAC,EAAG,CAC/D,MAAM,EAAS,CACb,OAAQ,EAAW,KAAK,oBACxB,MACF,CAAC,EACD,KAAK,KAAO,gBAEhB,CCHO,IAAM,EAAmB,CAAC,IAAmC,CAClE,IAAM,EAAQ,EAAS,MAAM,GAAG,EAEhC,GAAI,EAAM,SAAW,EACnB,MAAM,IAAI,EAAc,gCAAgC,GAAU,EAGpE,IAAM,EAAS,EAAM,GACf,EAAQ,OAAO,SAAS,EAAM,IAAM,IAAK,EAAE,EAC3C,EAAS,EAAM,GAErB,GAAI,OAAO,MAAM,CAAK,GAAK,GAAS,EAClC,MAAM,IAAI,EAAc,yCAAyC,EAAM,IAAI,EAI7E,GAAI,IAAW,KAAM,CACnB,IAAM,EAAM,IAAI,KAEhB,OAAQ,OACD,UAAW,CACd,IAAM,EAAgB,IAAI,KAAK,EAAI,QAAQ,EAAI,EAAQ,IAAI,EAC3D,MAAO,GAAG,EAAc,WAAW,KAAK,EAAc,SAAS,KAAK,EAAc,QAAQ,KAAK,EAAc,SAAS,EAAI,KAC5H,KAEK,UAAW,CACd,IAAM,EAAgB,IAAI,KAAK,EAAI,QAAQ,EAAI,EAAQ,GAAK,IAAI,EAChE,MAAO,GAAG,EAAc,WAAW,KAAK,EAAc,SAAS,KAAK,EAAc,QAAQ,KAAK,EAAc,SAAS,EAAI,KAC5H,KAEK,QAAS,CACZ,IAAM,EAAc,IAAI,KAAK,EAAI,QAAQ,EAAI,EAAQ,GAAK,GAAK,IAAI,EACnE,MAAO,GAAG,EAAY,WAAW,KAAK,EAAY,SAAS,KAAK,EAAY,QAAQ,KAAK,EAAY,SAAS,EAAI,KACpH,KAEK,OAAQ,CACX,IAAM,EAAa,IAAI,KAAK,EAAI,QAAQ,EAAI,EAAQ,GAAK,GAAK,GAAK,IAAI,EACvE,MAAO,GAAG,EAAW,WAAW,KAAK,EAAW,SAAS,KAAK,EAAW,QAAQ,KAAK,EAAW,SAAS,EAAI,KAChH,KAEK,SAAU,CACb,IAAM,EAAe,IAAI,KAAK,CAAG,EAEjC,OADA,EAAa,SAAS,EAAa,SAAS,EAAI,CAAK,EAC9C,GAAG,EAAa,WAAW,KAAK,EAAa,SAAS,KAAK,EAAa,QAAQ,KAAK,EAAa,SAAS,EAAI,KACxH,KAEK,QAAS,CACZ,IAAM,EAAc,IAAI,KAAK,CAAG,EAEhC,OADA,EAAY,YAAY,EAAY,YAAY,EAAI,CAAK,EAClD,GAAG,EAAY,WAAW,KAAK,EAAY,SAAS,KAAK,EAAY,QAAQ,KAAK,EAAY,SAAS,EAAI,KACpH,GAKJ,GAAI,IAAW,QACb,OAAQ,OACD,UACH,GAAI,IAAU,EAAG,MAAO,cACxB,MAAO,KAAK,kBAET,UACH,GAAI,IAAU,EAAG,MAAO,YACxB,MAAO,KAAK,gBAET,QACH,GAAI,IAAU,EAAG,MAAO,YACxB,MAAO,OAAO,cAEX,OACH,GAAI,IAAU,EAAG,MAAO,YACxB,MAAO,SAAS,YAEb,SACH,GAAI,IAAU,EAAG,MAAO,YACxB,MAAO,WAAW,UAEf,QACH,GAAI,IAAU,EAAG,MAAO,YACxB,MAAO,YAIb,MAAM,IAAI,EAAc,gCAAgC,GAAU,GFrF7D,MAAe,CAAsB,CAClC,QAA0B,UAMrB,MAAK,EAAkB,CAClC,GAAI,KAAK,SAAS,EAChB,OAGF,GAAI,KAAK,QAAS,CAChB,KAAK,QAAQ,MAAM,EACnB,OAGF,IAAM,EAAiB,EAAiB,KAAK,QAAQ,CAAC,EAEtD,GAAI,CACF,IAAM,EAKF,CACF,SAAU,EACV,OAAQ,SAAY,CAClB,MAAM,KAAK,IAAI,GAEjB,MAAO,EACT,EAEM,EAAW,KAAK,YAAY,EAClC,GAAI,IAAa,KACf,EAAW,SAAW,EAGxB,KAAK,QAAU,EAAQ,KAAK,CAAU,EACtC,MAAO,EAAO,CACd,MAAM,IAAI,EAAc,2BAA4B,CAClD,KAAM,KAAK,QAAQ,EACnB,iBACA,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAAC,QAIQ,KAAI,EAAkB,CACjC,GAAI,KAAK,QACP,KAAK,QAAQ,KAAK,EAIf,QAAQ,EAAY,CACzB,GAAI,CAAC,KAAK,QACR,MAAO,GAGT,OAAO,KAAK,QAAQ,SAExB,CGnEA,oBAAS,qBAAW,0BAGb,IAAM,EAAY,CACvB,KAAM,CAAC,EAAyB,EAAgB,YAAc,CAC5D,MAAO,CAAC,IAAgC,CACtC,EAAU,IAAI,EAAQ,CAAK,GAGjC,ECPO,IAAK,GAAL,CAAK,IAAL,CACL,KAAK,KACL,QAAQ,UAFE,QAKL,IAAK,GAAL,CAAK,IAAL,CACL,UAAU,UACV,UAAU,UACV,QAAQ,QACR,OAAO,OACP,SAAS,SACT,QAAQ,UANE",
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.1",
3
+ "description": "Scheduled task runner and cron job management with timezone support for Ooneex applications",
4
+ "version": "0.0.4",
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:prod": "bun publish --tolerate-republish --access public",
29
- "publish:pack": "bun pm pack --destination ./dist",
30
- "publish:dry": "bun publish --dry-run"
28
+ "publish": "bun publish --access public || true"
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
- "peerDependencies": {}
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