@hazeljs/cron 0.2.0-alpha.1

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.
@@ -0,0 +1,38 @@
1
+ import { CronService } from './cron.service';
2
+ /**
3
+ * Cron module options
4
+ */
5
+ export interface CronModuleOptions {
6
+ /**
7
+ * Whether this is a global module
8
+ * @default true
9
+ */
10
+ isGlobal?: boolean;
11
+ }
12
+ /**
13
+ * Cron module for HazelJS
14
+ * Provides scheduled job execution using cron expressions
15
+ */
16
+ export declare class CronModule {
17
+ /**
18
+ * Configure cron module
19
+ */
20
+ static forRoot(options?: CronModuleOptions): {
21
+ module: typeof CronModule;
22
+ providers: Array<typeof CronService>;
23
+ exports: Array<typeof CronService>;
24
+ global: boolean;
25
+ };
26
+ /**
27
+ * Manually register cron jobs from a provider instance
28
+ * Call this method after the provider has been instantiated
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const taskService = container.resolve(TaskService);
33
+ * CronModule.registerJobsFromProvider(taskService);
34
+ * ```
35
+ */
36
+ static registerJobsFromProvider(provider: object): void;
37
+ }
38
+ //# sourceMappingURL=cron.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron.module.d.ts","sourceRoot":"","sources":["../src/cron.module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAK7C;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,qBAIa,UAAU;IACrB;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,iBAAsB,GAAG;QAC/C,MAAM,EAAE,OAAO,UAAU,CAAC;QAC1B,SAAS,EAAE,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;QACrC,OAAO,EAAE,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;QACnC,MAAM,EAAE,OAAO,CAAC;KACjB;IAaD;;;;;;;;;OASG;IACH,MAAM,CAAC,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;CAgCxD"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ var CronModule_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.CronModule = void 0;
14
+ const core_1 = require("@hazeljs/core");
15
+ const cron_service_1 = require("./cron.service");
16
+ const cron_decorator_1 = require("./cron.decorator");
17
+ const core_2 = require("@hazeljs/core");
18
+ const core_3 = __importDefault(require("@hazeljs/core"));
19
+ /**
20
+ * Cron module for HazelJS
21
+ * Provides scheduled job execution using cron expressions
22
+ */
23
+ let CronModule = CronModule_1 = class CronModule {
24
+ /**
25
+ * Configure cron module
26
+ */
27
+ static forRoot(options = {}) {
28
+ const { isGlobal = true } = options;
29
+ core_3.default.info('Configuring cron module...');
30
+ return {
31
+ module: CronModule_1,
32
+ providers: [cron_service_1.CronService],
33
+ exports: [cron_service_1.CronService],
34
+ global: isGlobal,
35
+ };
36
+ }
37
+ /**
38
+ * Manually register cron jobs from a provider instance
39
+ * Call this method after the provider has been instantiated
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const taskService = container.resolve(TaskService);
44
+ * CronModule.registerJobsFromProvider(taskService);
45
+ * ```
46
+ */
47
+ static registerJobsFromProvider(provider) {
48
+ try {
49
+ const container = core_2.Container.getInstance();
50
+ const cronService = container.resolve(cron_service_1.CronService);
51
+ if (!cronService) {
52
+ core_3.default.warn('CronService not found in DI container');
53
+ return;
54
+ }
55
+ const metadata = (0, cron_decorator_1.getCronMetadata)(provider);
56
+ if (metadata && metadata.length > 0) {
57
+ for (const job of metadata) {
58
+ const instance = provider;
59
+ const callback = instance[job.methodName];
60
+ if (typeof callback === 'function') {
61
+ cronService.registerJob(job.options.name || job.methodName, job.options.cronTime, callback.bind(instance), job.options);
62
+ core_3.default.info(`Registered cron job: ${job.options.name || job.methodName}`);
63
+ }
64
+ }
65
+ }
66
+ }
67
+ catch (error) {
68
+ core_3.default.error('Error registering cron jobs from provider:', error);
69
+ }
70
+ }
71
+ };
72
+ exports.CronModule = CronModule;
73
+ exports.CronModule = CronModule = CronModule_1 = __decorate([
74
+ (0, core_1.HazelModule)({
75
+ providers: [cron_service_1.CronService],
76
+ exports: [cron_service_1.CronService],
77
+ })
78
+ ], CronModule);
@@ -0,0 +1,56 @@
1
+ import { CronOptions, CronJobStatus } from './cron.types';
2
+ /**
3
+ * Cron service for managing scheduled jobs
4
+ */
5
+ export declare class CronService {
6
+ private jobs;
7
+ /**
8
+ * Register a new cron job
9
+ */
10
+ registerJob(name: string, cronExpression: string, callback: () => void | Promise<void>, options?: CronOptions): void;
11
+ /**
12
+ * Delete a cron job
13
+ */
14
+ deleteJob(name: string): boolean;
15
+ /**
16
+ * Start a specific job
17
+ */
18
+ startJob(name: string): boolean;
19
+ /**
20
+ * Stop a specific job
21
+ */
22
+ stopJob(name: string): boolean;
23
+ /**
24
+ * Enable a job
25
+ */
26
+ enableJob(name: string): boolean;
27
+ /**
28
+ * Disable a job
29
+ */
30
+ disableJob(name: string): boolean;
31
+ /**
32
+ * Get status of a specific job
33
+ */
34
+ getJobStatus(name: string): CronJobStatus | undefined;
35
+ /**
36
+ * Get status of all jobs
37
+ */
38
+ getAllJobStatuses(): CronJobStatus[];
39
+ /**
40
+ * Stop all jobs
41
+ */
42
+ stopAll(): void;
43
+ /**
44
+ * Start all jobs
45
+ */
46
+ startAll(): void;
47
+ /**
48
+ * Clear all jobs
49
+ */
50
+ clearAll(): void;
51
+ /**
52
+ * Get number of registered jobs
53
+ */
54
+ getJobCount(): number;
55
+ }
56
+ //# sourceMappingURL=cron.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron.service.d.ts","sourceRoot":"","sources":["../src/cron.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAgK1D;;GAEG;AACH,qBACa,WAAW;IACtB,OAAO,CAAC,IAAI,CAA8B;IAE1C;;OAEG;IACH,WAAW,CACT,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EACpC,OAAO,GAAE,WAA0C,GAClD,IAAI;IAeP;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAWhC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAU/B;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAU9B;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAUhC;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAUjC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAKrD;;OAEG;IACH,iBAAiB,IAAI,aAAa,EAAE;IAIpC;;OAEG;IACH,OAAO,IAAI,IAAI;IAKf;;OAEG;IACH,QAAQ,IAAI,IAAI;IAKhB;;OAEG;IACH,QAAQ,IAAI,IAAI;IAMhB;;OAEG;IACH,WAAW,IAAI,MAAM;CAGtB"}
@@ -0,0 +1,273 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.CronService = void 0;
13
+ const core_1 = require("@hazeljs/core");
14
+ const core_2 = __importDefault(require("@hazeljs/core"));
15
+ const node_cron_1 = __importDefault(require("node-cron"));
16
+ /**
17
+ * Represents a scheduled cron job
18
+ * Uses node-cron for proper cron expression parsing and scheduling
19
+ */
20
+ class CronJob {
21
+ constructor(name, cronExpression, callback, options) {
22
+ this.name = name;
23
+ this.cronExpression = cronExpression;
24
+ this.callback = callback;
25
+ this.options = options;
26
+ this.task = null;
27
+ this._isRunning = false;
28
+ this._runCount = 0;
29
+ this._enabled = true;
30
+ this._enabled = options.enabled !== false;
31
+ // node-cron uses 5-field (minute-level) or 6-field (second-level) expressions
32
+ // Validate the expression upfront
33
+ const expr = this.normalizeExpression(this.cronExpression);
34
+ if (!node_cron_1.default.validate(expr)) {
35
+ throw new Error(`Invalid cron expression: ${this.cronExpression}. ` +
36
+ `Format: second minute hour day-of-month month day-of-week`);
37
+ }
38
+ }
39
+ /**
40
+ * Normalize expression for node-cron compatibility
41
+ * node-cron supports both 5-field (no seconds) and 6-field (with seconds)
42
+ */
43
+ normalizeExpression(expression) {
44
+ return expression;
45
+ }
46
+ /**
47
+ * Start the cron job
48
+ */
49
+ start() {
50
+ if (this.task) {
51
+ core_2.default.warn(`Cron job "${this.name}" is already running`);
52
+ return;
53
+ }
54
+ if (!this._enabled) {
55
+ core_2.default.warn(`Cron job "${this.name}" is disabled`);
56
+ return;
57
+ }
58
+ const expr = this.normalizeExpression(this.cronExpression);
59
+ this.task = node_cron_1.default.schedule(expr, async () => {
60
+ await this.execute();
61
+ }, {
62
+ scheduled: true,
63
+ timezone: this.options.timeZone,
64
+ });
65
+ // Run on init if specified
66
+ if (this.options.runOnInit) {
67
+ this.execute();
68
+ }
69
+ core_2.default.info(`Cron job "${this.name}" started with expression: ${this.cronExpression}`);
70
+ }
71
+ /**
72
+ * Stop the cron job
73
+ */
74
+ stop() {
75
+ if (this.task) {
76
+ this.task.stop();
77
+ this.task = null;
78
+ this._nextExecution = undefined;
79
+ core_2.default.info(`Cron job "${this.name}" stopped`);
80
+ }
81
+ }
82
+ /**
83
+ * Execute the job
84
+ */
85
+ async execute() {
86
+ if (this._isRunning) {
87
+ core_2.default.warn(`Cron job "${this.name}" is already executing, skipping this run`);
88
+ return;
89
+ }
90
+ // Check max runs
91
+ if (this.options.maxRuns && this._runCount >= this.options.maxRuns) {
92
+ core_2.default.info(`Cron job "${this.name}" reached max runs (${this.options.maxRuns}), stopping`);
93
+ this.stop();
94
+ return;
95
+ }
96
+ this._isRunning = true;
97
+ this._lastExecution = new Date();
98
+ this._runCount++;
99
+ try {
100
+ core_2.default.debug(`Executing cron job "${this.name}" (run #${this._runCount})`);
101
+ await this.callback();
102
+ if (this.options.onComplete) {
103
+ this.options.onComplete();
104
+ }
105
+ }
106
+ catch (error) {
107
+ core_2.default.error(`Error executing cron job "${this.name}":`, error);
108
+ if (this.options.onError) {
109
+ this.options.onError(error);
110
+ }
111
+ }
112
+ finally {
113
+ this._isRunning = false;
114
+ }
115
+ }
116
+ /**
117
+ * Enable the job
118
+ */
119
+ enable() {
120
+ this._enabled = true;
121
+ core_2.default.info(`Cron job "${this.name}" enabled`);
122
+ }
123
+ /**
124
+ * Disable the job
125
+ */
126
+ disable() {
127
+ this._enabled = false;
128
+ this.stop();
129
+ core_2.default.info(`Cron job "${this.name}" disabled`);
130
+ }
131
+ /**
132
+ * Get job status
133
+ */
134
+ getStatus() {
135
+ return {
136
+ name: this.name,
137
+ isRunning: this._isRunning,
138
+ lastExecution: this._lastExecution,
139
+ nextExecution: this._nextExecution,
140
+ runCount: this._runCount,
141
+ enabled: this._enabled,
142
+ };
143
+ }
144
+ }
145
+ /**
146
+ * Cron service for managing scheduled jobs
147
+ */
148
+ let CronService = class CronService {
149
+ constructor() {
150
+ this.jobs = new Map();
151
+ }
152
+ /**
153
+ * Register a new cron job
154
+ */
155
+ registerJob(name, cronExpression, callback, options = { cronTime: cronExpression }) {
156
+ if (this.jobs.has(name)) {
157
+ core_2.default.warn(`Cron job "${name}" already exists, replacing it`);
158
+ this.deleteJob(name);
159
+ }
160
+ const job = new CronJob(name, cronExpression, callback, options);
161
+ this.jobs.set(name, job);
162
+ // Auto-start if not explicitly disabled
163
+ if (options.enabled !== false) {
164
+ job.start();
165
+ }
166
+ }
167
+ /**
168
+ * Delete a cron job
169
+ */
170
+ deleteJob(name) {
171
+ const job = this.jobs.get(name);
172
+ if (job) {
173
+ job.stop();
174
+ this.jobs.delete(name);
175
+ core_2.default.info(`Cron job "${name}" deleted`);
176
+ return true;
177
+ }
178
+ return false;
179
+ }
180
+ /**
181
+ * Start a specific job
182
+ */
183
+ startJob(name) {
184
+ const job = this.jobs.get(name);
185
+ if (job) {
186
+ job.start();
187
+ return true;
188
+ }
189
+ core_2.default.warn(`Cron job "${name}" not found`);
190
+ return false;
191
+ }
192
+ /**
193
+ * Stop a specific job
194
+ */
195
+ stopJob(name) {
196
+ const job = this.jobs.get(name);
197
+ if (job) {
198
+ job.stop();
199
+ return true;
200
+ }
201
+ core_2.default.warn(`Cron job "${name}" not found`);
202
+ return false;
203
+ }
204
+ /**
205
+ * Enable a job
206
+ */
207
+ enableJob(name) {
208
+ const job = this.jobs.get(name);
209
+ if (job) {
210
+ job.enable();
211
+ return true;
212
+ }
213
+ core_2.default.warn(`Cron job "${name}" not found`);
214
+ return false;
215
+ }
216
+ /**
217
+ * Disable a job
218
+ */
219
+ disableJob(name) {
220
+ const job = this.jobs.get(name);
221
+ if (job) {
222
+ job.disable();
223
+ return true;
224
+ }
225
+ core_2.default.warn(`Cron job "${name}" not found`);
226
+ return false;
227
+ }
228
+ /**
229
+ * Get status of a specific job
230
+ */
231
+ getJobStatus(name) {
232
+ const job = this.jobs.get(name);
233
+ return job?.getStatus();
234
+ }
235
+ /**
236
+ * Get status of all jobs
237
+ */
238
+ getAllJobStatuses() {
239
+ return Array.from(this.jobs.values()).map((job) => job.getStatus());
240
+ }
241
+ /**
242
+ * Stop all jobs
243
+ */
244
+ stopAll() {
245
+ this.jobs.forEach((job) => job.stop());
246
+ core_2.default.info('All cron jobs stopped');
247
+ }
248
+ /**
249
+ * Start all jobs
250
+ */
251
+ startAll() {
252
+ this.jobs.forEach((job) => job.start());
253
+ core_2.default.info('All cron jobs started');
254
+ }
255
+ /**
256
+ * Clear all jobs
257
+ */
258
+ clearAll() {
259
+ this.stopAll();
260
+ this.jobs.clear();
261
+ core_2.default.info('All cron jobs cleared');
262
+ }
263
+ /**
264
+ * Get number of registered jobs
265
+ */
266
+ getJobCount() {
267
+ return this.jobs.size;
268
+ }
269
+ };
270
+ exports.CronService = CronService;
271
+ exports.CronService = CronService = __decorate([
272
+ (0, core_1.Service)()
273
+ ], CronService);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cron.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron.test.d.ts","sourceRoot":"","sources":["../src/cron.test.ts"],"names":[],"mappings":""}