@qodalis/cli-server-plugin-jobs 1.0.0-beta.12

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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +94 -0
  3. package/dist/cli-job-execution-context.d.ts +10 -0
  4. package/dist/cli-job-execution-context.d.ts.map +1 -0
  5. package/dist/cli-job-execution-context.js +19 -0
  6. package/dist/cli-job-execution-context.js.map +1 -0
  7. package/dist/cli-job-logger.d.ts +13 -0
  8. package/dist/cli-job-logger.d.ts.map +1 -0
  9. package/dist/cli-job-logger.js +32 -0
  10. package/dist/cli-job-logger.js.map +1 -0
  11. package/dist/cli-job-scheduler.d.ts +107 -0
  12. package/dist/cli-job-scheduler.d.ts.map +1 -0
  13. package/dist/cli-job-scheduler.js +462 -0
  14. package/dist/cli-job-scheduler.js.map +1 -0
  15. package/dist/cli-jobs-builder.d.ts +46 -0
  16. package/dist/cli-jobs-builder.d.ts.map +1 -0
  17. package/dist/cli-jobs-builder.js +59 -0
  18. package/dist/cli-jobs-builder.js.map +1 -0
  19. package/dist/cli-jobs-controller.d.ts +24 -0
  20. package/dist/cli-jobs-controller.d.ts.map +1 -0
  21. package/dist/cli-jobs-controller.js +150 -0
  22. package/dist/cli-jobs-controller.js.map +1 -0
  23. package/dist/in-memory-job-storage-provider.d.ts +22 -0
  24. package/dist/in-memory-job-storage-provider.d.ts.map +1 -0
  25. package/dist/in-memory-job-storage-provider.js +50 -0
  26. package/dist/in-memory-job-storage-provider.js.map +1 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +19 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/interval-parser.d.ts +6 -0
  32. package/dist/interval-parser.d.ts.map +1 -0
  33. package/dist/interval-parser.js +25 -0
  34. package/dist/interval-parser.js.map +1 -0
  35. package/dist/tsconfig.tsbuildinfo +1 -0
  36. package/package.json +40 -0
@@ -0,0 +1,462 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JobError = exports.CliJobScheduler = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const cron_parser_1 = require("cron-parser");
6
+ const cli_job_execution_context_1 = require("./cli-job-execution-context");
7
+ const interval_parser_1 = require("./interval-parser");
8
+ /**
9
+ * Manages job registration, scheduling (cron / interval), execution with
10
+ * retry logic, overlap policies, and state persistence.
11
+ */
12
+ class CliJobScheduler {
13
+ _registrations = new Map();
14
+ _storage;
15
+ _broadcastFn = null;
16
+ _running = false;
17
+ constructor(storage) {
18
+ this._storage = storage;
19
+ }
20
+ /** Set the function used to broadcast job lifecycle events (e.g. via WebSocket). */
21
+ setBroadcastFn(fn) {
22
+ this._broadcastFn = fn;
23
+ }
24
+ /**
25
+ * Register a job with the scheduler.
26
+ *
27
+ * @param job - The job implementation.
28
+ * @param options - Scheduling and retry configuration.
29
+ * @returns The generated job ID.
30
+ */
31
+ register(job, options) {
32
+ const id = (0, crypto_1.randomUUID)();
33
+ const enabled = options.enabled !== false;
34
+ const reg = {
35
+ id,
36
+ job,
37
+ options: { ...options, enabled },
38
+ status: enabled ? 'active' : 'stopped',
39
+ queue: [],
40
+ };
41
+ this._registrations.set(id, reg);
42
+ return id;
43
+ }
44
+ /** Load persisted job states and start timers for all active jobs. */
45
+ async start() {
46
+ this._running = true;
47
+ // Load persisted states
48
+ const states = await this._storage.getAllJobStates();
49
+ for (const [id, reg] of this._registrations) {
50
+ const persisted = states.get(id);
51
+ if (persisted) {
52
+ reg.status = persisted.status;
53
+ reg.lastRunAt = persisted.lastRunAt;
54
+ }
55
+ if (reg.status === 'active') {
56
+ this._startTimer(reg);
57
+ }
58
+ }
59
+ }
60
+ /** Stop all timers, cancel running executions, and persist final states. */
61
+ async stop() {
62
+ this._running = false;
63
+ // Cancel all running executions and stop timers
64
+ for (const reg of this._registrations.values()) {
65
+ this._stopTimer(reg);
66
+ if (reg.currentAbortController) {
67
+ reg.currentAbortController.abort();
68
+ }
69
+ // Persist state
70
+ await this._storage.saveJobState(reg.id, {
71
+ status: reg.status,
72
+ lastRunAt: reg.lastRunAt,
73
+ updatedAt: new Date().toISOString(),
74
+ });
75
+ }
76
+ }
77
+ /** Return DTOs for all registered jobs. */
78
+ getAll() {
79
+ return Array.from(this._registrations.values()).map((reg) => this._toDto(reg));
80
+ }
81
+ /** Return the DTO for a single job, or `undefined` if not found. */
82
+ get(id) {
83
+ const reg = this._registrations.get(id);
84
+ return reg ? this._toDto(reg) : undefined;
85
+ }
86
+ /** Return the internal registration for a job (used by the controller for history lookups). */
87
+ getRegistration(id) {
88
+ return this._registrations.get(id);
89
+ }
90
+ /**
91
+ * Trigger an immediate execution of a job, respecting the configured overlap policy.
92
+ *
93
+ * @throws {JobError} If the job is not found or is already running with a 'skip' policy.
94
+ */
95
+ async triggerAsync(id) {
96
+ const reg = this._registrations.get(id);
97
+ if (!reg)
98
+ throw new JobError('Job not found', 'JOB_NOT_FOUND', 404);
99
+ if (reg.currentExecutionId) {
100
+ const policy = reg.options.overlapPolicy ?? 'skip';
101
+ if (policy === 'skip') {
102
+ throw new JobError('Job is already running', 'JOB_ALREADY_RUNNING', 409);
103
+ }
104
+ if (policy === 'cancel') {
105
+ reg.currentAbortController?.abort();
106
+ // Wait briefly for cancellation
107
+ await new Promise((r) => setTimeout(r, 50));
108
+ }
109
+ if (policy === 'queue') {
110
+ return new Promise((resolve) => {
111
+ reg.queue.push({ resolve });
112
+ });
113
+ }
114
+ }
115
+ await this._executeJobAsync(reg, 0);
116
+ }
117
+ /** Pause a running job's schedule without cancelling the current execution. */
118
+ async pauseAsync(id) {
119
+ const reg = this._registrations.get(id);
120
+ if (!reg)
121
+ throw new JobError('Job not found', 'JOB_NOT_FOUND', 404);
122
+ if (reg.status === 'paused')
123
+ throw new JobError('Job is already paused', 'JOB_ALREADY_PAUSED', 409);
124
+ reg.status = 'paused';
125
+ this._stopTimer(reg);
126
+ await this._persistState(reg);
127
+ this._broadcast({ type: 'job:paused', jobId: reg.id });
128
+ }
129
+ /** Resume a paused job, restarting its schedule timer. */
130
+ async resumeAsync(id) {
131
+ const reg = this._registrations.get(id);
132
+ if (!reg)
133
+ throw new JobError('Job not found', 'JOB_NOT_FOUND', 404);
134
+ if (reg.status !== 'paused')
135
+ throw new JobError('Job is not paused', 'JOB_NOT_PAUSED', 409);
136
+ reg.status = 'active';
137
+ this._startTimer(reg);
138
+ await this._persistState(reg);
139
+ this._broadcast({ type: 'job:resumed', jobId: reg.id });
140
+ }
141
+ /** Stop a job entirely, cancelling any running execution and clearing its timer. */
142
+ async stopJobAsync(id) {
143
+ const reg = this._registrations.get(id);
144
+ if (!reg)
145
+ throw new JobError('Job not found', 'JOB_NOT_FOUND', 404);
146
+ reg.status = 'stopped';
147
+ this._stopTimer(reg);
148
+ if (reg.currentAbortController) {
149
+ reg.currentAbortController.abort();
150
+ }
151
+ await this._persistState(reg);
152
+ this._broadcast({ type: 'job:stopped', jobId: reg.id });
153
+ }
154
+ /** Cancel the currently running execution of a job without changing its schedule. */
155
+ async cancelCurrentAsync(id) {
156
+ const reg = this._registrations.get(id);
157
+ if (!reg)
158
+ throw new JobError('Job not found', 'JOB_NOT_FOUND', 404);
159
+ if (!reg.currentExecutionId)
160
+ throw new JobError('No execution is running', 'JOB_NOT_RUNNING', 409);
161
+ reg.currentAbortController?.abort();
162
+ }
163
+ /** Update mutable job options (schedule, retry policy, etc.) and restart timers if active. */
164
+ async updateOptionsAsync(id, updates) {
165
+ const reg = this._registrations.get(id);
166
+ if (!reg)
167
+ throw new JobError('Job not found', 'JOB_NOT_FOUND', 404);
168
+ // Validate: can't provide both schedule and interval
169
+ if (updates.schedule !== undefined && updates.interval !== undefined && updates.schedule !== null && updates.interval !== null) {
170
+ throw new JobError('Cannot provide both schedule and interval', 'SCHEDULE_CONFLICT', 400);
171
+ }
172
+ // Validate schedule if provided
173
+ if (updates.schedule !== undefined && updates.schedule !== null) {
174
+ try {
175
+ cron_parser_1.CronExpressionParser.parse(updates.schedule);
176
+ }
177
+ catch {
178
+ throw new JobError('Invalid cron expression', 'INVALID_SCHEDULE', 400);
179
+ }
180
+ }
181
+ // Validate interval if provided
182
+ if (updates.interval !== undefined && updates.interval !== null) {
183
+ const ms = (0, interval_parser_1.parseInterval)(updates.interval);
184
+ if (ms === null) {
185
+ throw new JobError('Invalid interval format', 'INVALID_SCHEDULE', 400);
186
+ }
187
+ }
188
+ // Apply updates
189
+ if (updates.description !== undefined)
190
+ reg.options.description = updates.description;
191
+ if (updates.group !== undefined)
192
+ reg.options.group = updates.group;
193
+ if (updates.maxRetries !== undefined)
194
+ reg.options.maxRetries = updates.maxRetries;
195
+ if (updates.retryDelay !== undefined)
196
+ reg.options.retryDelay = updates.retryDelay;
197
+ if (updates.retryStrategy !== undefined)
198
+ reg.options.retryStrategy = updates.retryStrategy;
199
+ if (updates.timeout !== undefined)
200
+ reg.options.timeout = updates.timeout;
201
+ if (updates.overlapPolicy !== undefined)
202
+ reg.options.overlapPolicy = updates.overlapPolicy;
203
+ // Handle schedule/interval changes (setting one clears the other)
204
+ if (updates.schedule !== undefined) {
205
+ if (updates.schedule === null) {
206
+ reg.options.schedule = undefined;
207
+ }
208
+ else {
209
+ reg.options.schedule = updates.schedule;
210
+ reg.options.interval = undefined;
211
+ }
212
+ }
213
+ if (updates.interval !== undefined) {
214
+ if (updates.interval === null) {
215
+ reg.options.interval = undefined;
216
+ }
217
+ else {
218
+ reg.options.interval = updates.interval;
219
+ reg.options.schedule = undefined;
220
+ }
221
+ }
222
+ // Restart timer if active
223
+ if (reg.status === 'active') {
224
+ this._stopTimer(reg);
225
+ this._startTimer(reg);
226
+ }
227
+ }
228
+ get storage() {
229
+ return this._storage;
230
+ }
231
+ _toDto(reg) {
232
+ return {
233
+ id: reg.id,
234
+ name: reg.options.name ?? 'unnamed',
235
+ description: reg.options.description ?? reg.options.name ?? 'unnamed',
236
+ group: reg.options.group,
237
+ status: reg.status,
238
+ schedule: reg.options.schedule,
239
+ interval: reg.options.interval,
240
+ enabled: reg.options.enabled !== false,
241
+ maxRetries: reg.options.maxRetries ?? 1,
242
+ retryDelay: reg.options.retryDelay ?? '5s',
243
+ retryStrategy: reg.options.retryStrategy ?? 'exponential',
244
+ timeout: reg.options.timeout,
245
+ overlapPolicy: reg.options.overlapPolicy ?? 'skip',
246
+ currentExecutionId: reg.currentExecutionId,
247
+ nextRunAt: reg.nextRunAt,
248
+ lastRunAt: reg.lastRunAt,
249
+ lastRunStatus: reg.lastRunStatus,
250
+ lastRunDuration: reg.lastRunDuration,
251
+ };
252
+ }
253
+ _startTimer(reg) {
254
+ if (reg.options.schedule) {
255
+ this._startCronTimer(reg);
256
+ }
257
+ else if (reg.options.interval) {
258
+ this._startIntervalTimer(reg);
259
+ }
260
+ }
261
+ _startCronTimer(reg) {
262
+ const scheduleNext = () => {
263
+ if (!this._running || reg.status !== 'active')
264
+ return;
265
+ try {
266
+ const expr = cron_parser_1.CronExpressionParser.parse(reg.options.schedule);
267
+ const next = expr.next();
268
+ const nextDate = next.toDate();
269
+ reg.nextRunAt = nextDate.toISOString();
270
+ const delay = nextDate.getTime() - Date.now();
271
+ reg.timer = setTimeout(async () => {
272
+ if (reg.status !== 'active' || !this._running)
273
+ return;
274
+ await this._handleTimerFire(reg);
275
+ scheduleNext();
276
+ }, Math.max(delay, 0));
277
+ reg.timerType = 'cron';
278
+ }
279
+ catch {
280
+ // Invalid cron expression — stop scheduling
281
+ }
282
+ };
283
+ scheduleNext();
284
+ }
285
+ _startIntervalTimer(reg) {
286
+ const ms = (0, interval_parser_1.parseInterval)(reg.options.interval);
287
+ if (ms === null)
288
+ return;
289
+ reg.nextRunAt = new Date(Date.now() + ms).toISOString();
290
+ reg.timer = setInterval(async () => {
291
+ if (reg.status !== 'active' || !this._running)
292
+ return;
293
+ await this._handleTimerFire(reg);
294
+ reg.nextRunAt = new Date(Date.now() + ms).toISOString();
295
+ }, ms);
296
+ reg.timerType = 'interval';
297
+ }
298
+ async _handleTimerFire(reg) {
299
+ if (reg.currentExecutionId) {
300
+ const policy = reg.options.overlapPolicy ?? 'skip';
301
+ if (policy === 'skip')
302
+ return;
303
+ if (policy === 'cancel') {
304
+ reg.currentAbortController?.abort();
305
+ await new Promise((r) => setTimeout(r, 50));
306
+ }
307
+ if (policy === 'queue') {
308
+ return new Promise((resolve) => {
309
+ reg.queue.push({ resolve });
310
+ });
311
+ }
312
+ }
313
+ await this._executeJobAsync(reg, 0);
314
+ }
315
+ async _executeJobAsync(reg, retryAttempt) {
316
+ const executionId = (0, crypto_1.randomUUID)();
317
+ const abortController = new AbortController();
318
+ reg.currentExecutionId = executionId;
319
+ reg.currentAbortController = abortController;
320
+ const execution = {
321
+ id: executionId,
322
+ jobId: reg.id,
323
+ jobName: reg.options.name ?? 'unnamed',
324
+ status: 'running',
325
+ startedAt: new Date().toISOString(),
326
+ logs: [],
327
+ retryAttempt,
328
+ };
329
+ await this._storage.saveExecution(execution);
330
+ this._broadcast({
331
+ type: 'job:started',
332
+ jobId: reg.id,
333
+ executionId,
334
+ timestamp: execution.startedAt,
335
+ });
336
+ const context = new cli_job_execution_context_1.CliJobExecutionContext();
337
+ let timeoutTimer;
338
+ // Set up timeout
339
+ if (reg.options.timeout) {
340
+ const timeoutMs = (0, interval_parser_1.parseInterval)(reg.options.timeout);
341
+ if (timeoutMs !== null) {
342
+ timeoutTimer = setTimeout(() => {
343
+ abortController.abort();
344
+ }, timeoutMs);
345
+ }
346
+ }
347
+ let finalStatus = 'completed';
348
+ let error;
349
+ try {
350
+ await reg.job.executeAsync(context, abortController.signal);
351
+ if (abortController.signal.aborted) {
352
+ // Determine if this was a timeout or manual cancel
353
+ finalStatus = timeoutTimer ? 'timed_out' : 'cancelled';
354
+ }
355
+ }
356
+ catch (err) {
357
+ if (abortController.signal.aborted) {
358
+ finalStatus = timeoutTimer ? 'timed_out' : 'cancelled';
359
+ }
360
+ else {
361
+ finalStatus = 'failed';
362
+ error = err instanceof Error ? err.message : String(err);
363
+ }
364
+ }
365
+ finally {
366
+ if (timeoutTimer)
367
+ clearTimeout(timeoutTimer);
368
+ }
369
+ const completedAt = new Date();
370
+ const duration = completedAt.getTime() - new Date(execution.startedAt).getTime();
371
+ execution.status = finalStatus;
372
+ execution.completedAt = completedAt.toISOString();
373
+ execution.duration = duration;
374
+ execution.error = error;
375
+ execution.logs = context.logEntries;
376
+ await this._storage.saveExecution(execution);
377
+ reg.currentExecutionId = undefined;
378
+ reg.currentAbortController = undefined;
379
+ reg.lastRunAt = execution.startedAt;
380
+ reg.lastRunStatus = finalStatus;
381
+ reg.lastRunDuration = duration;
382
+ // Persist state
383
+ await this._persistState(reg);
384
+ // Broadcast completion event
385
+ if (finalStatus === 'completed') {
386
+ this._broadcast({ type: 'job:completed', jobId: reg.id, executionId, duration });
387
+ }
388
+ else if (finalStatus === 'failed') {
389
+ this._broadcast({ type: 'job:failed', jobId: reg.id, executionId, error });
390
+ }
391
+ else if (finalStatus === 'cancelled') {
392
+ this._broadcast({ type: 'job:cancelled', jobId: reg.id, executionId });
393
+ }
394
+ else if (finalStatus === 'timed_out') {
395
+ this._broadcast({ type: 'job:timed_out', jobId: reg.id, executionId, timeout: reg.options.timeout });
396
+ }
397
+ // Handle retry on failure
398
+ if (finalStatus === 'failed' && retryAttempt < (reg.options.maxRetries ?? 1)) {
399
+ const baseDelay = (0, interval_parser_1.parseInterval)(reg.options.retryDelay ?? '5s') ?? 5000;
400
+ const strategy = reg.options.retryStrategy ?? 'exponential';
401
+ const delay = strategy === 'fixed' ? baseDelay
402
+ : strategy === 'linear' ? baseDelay * (retryAttempt + 1)
403
+ : baseDelay * Math.pow(2, retryAttempt);
404
+ this._broadcast({
405
+ type: 'job:retrying',
406
+ jobId: reg.id,
407
+ executionId,
408
+ attempt: retryAttempt + 1,
409
+ maxRetries: reg.options.maxRetries ?? 1,
410
+ delayMs: delay,
411
+ });
412
+ await new Promise(resolve => setTimeout(resolve, delay));
413
+ await this._executeJobAsync(reg, retryAttempt + 1);
414
+ return;
415
+ }
416
+ // Process queue
417
+ if (reg.queue.length > 0) {
418
+ const next = reg.queue.shift();
419
+ next.resolve();
420
+ await this._executeJobAsync(reg, 0);
421
+ }
422
+ }
423
+ _stopTimer(reg) {
424
+ if (reg.timer !== undefined) {
425
+ if (reg.timerType === 'interval') {
426
+ clearInterval(reg.timer);
427
+ }
428
+ else {
429
+ clearTimeout(reg.timer);
430
+ }
431
+ reg.timer = undefined;
432
+ reg.timerType = undefined;
433
+ }
434
+ reg.nextRunAt = undefined;
435
+ }
436
+ async _persistState(reg) {
437
+ await this._storage.saveJobState(reg.id, {
438
+ status: reg.status,
439
+ lastRunAt: reg.lastRunAt,
440
+ updatedAt: new Date().toISOString(),
441
+ });
442
+ }
443
+ _broadcast(message) {
444
+ if (this._broadcastFn) {
445
+ this._broadcastFn(message);
446
+ }
447
+ }
448
+ }
449
+ exports.CliJobScheduler = CliJobScheduler;
450
+ /** Typed error thrown by the scheduler, carrying an error code and HTTP status. */
451
+ class JobError extends Error {
452
+ code;
453
+ statusCode;
454
+ constructor(message, code, statusCode) {
455
+ super(message);
456
+ this.code = code;
457
+ this.statusCode = statusCode;
458
+ this.name = 'JobError';
459
+ }
460
+ }
461
+ exports.JobError = JobError;
462
+ //# sourceMappingURL=cli-job-scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-job-scheduler.js","sourceRoot":"","sources":["../cli-job-scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { ICliJob, CliJobOptions, ICliJobStorageProvider } from '@qodalis/cli-server-abstractions';
2
+ import { Router } from 'express';
3
+ import { CliJobScheduler } from './cli-job-scheduler';
4
+ export interface CliJobsPluginResult {
5
+ /** Default mount prefix for this plugin. */
6
+ prefix: '/api/v1/qcli/jobs';
7
+ /** Express router for the jobs API. */
8
+ router: Router;
9
+ /** The job scheduler instance. Call `start()` / `stop()` to manage its lifecycle. */
10
+ scheduler: CliJobScheduler;
11
+ }
12
+ /**
13
+ * Fluent builder for configuring the jobs plugin independently of the core CLI server.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { CliJobsBuilder } from '@qodalis/cli-server-plugin-jobs';
18
+ *
19
+ * const jobsPlugin = new CliJobsBuilder()
20
+ * .addJob(new SampleHealthCheckJob(), { name: 'health-check', interval: '30s' })
21
+ * .build((msg) => eventSocketManager.broadcastMessage(msg));
22
+ *
23
+ * app.use('/api/v1/qcli/jobs', jobsPlugin.router);
24
+ * await jobsPlugin.scheduler.start();
25
+ * ```
26
+ */
27
+ export declare class CliJobsBuilder {
28
+ private readonly _jobs;
29
+ private _storageProvider?;
30
+ /**
31
+ * Register a job to be managed by the scheduler.
32
+ */
33
+ addJob(job: ICliJob, options: CliJobOptions): CliJobsBuilder;
34
+ /**
35
+ * Set a custom storage provider for job state and execution history.
36
+ * If not set, an in-memory provider will be used.
37
+ */
38
+ setStorageProvider(provider: ICliJobStorageProvider): CliJobsBuilder;
39
+ /**
40
+ * Build the plugin, returning the Express router and scheduler.
41
+ *
42
+ * @param broadcastFn Optional function to broadcast job events (e.g. via WebSocket).
43
+ */
44
+ build(broadcastFn?: (message: Record<string, unknown>) => void): CliJobsPluginResult;
45
+ }
46
+ //# sourceMappingURL=cli-jobs-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-jobs-builder.d.ts","sourceRoot":"","sources":["../cli-jobs-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAClG,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAItD,MAAM,WAAW,mBAAmB;IAChC,4CAA4C;IAC5C,MAAM,EAAE,mBAAmB,CAAC;IAC5B,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,qFAAqF;IACrF,SAAS,EAAE,eAAe,CAAC;CAC9B;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuD;IAC7E,OAAO,CAAC,gBAAgB,CAAC,CAAyB;IAElD;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,GAAG,cAAc;IAK5D;;;OAGG;IACH,kBAAkB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,cAAc;IAKpE;;;;OAIG;IACH,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,mBAAmB;CAgBvF"}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CliJobsBuilder = void 0;
4
+ const cli_job_scheduler_1 = require("./cli-job-scheduler");
5
+ const in_memory_job_storage_provider_1 = require("./in-memory-job-storage-provider");
6
+ const cli_jobs_controller_1 = require("./cli-jobs-controller");
7
+ /**
8
+ * Fluent builder for configuring the jobs plugin independently of the core CLI server.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { CliJobsBuilder } from '@qodalis/cli-server-plugin-jobs';
13
+ *
14
+ * const jobsPlugin = new CliJobsBuilder()
15
+ * .addJob(new SampleHealthCheckJob(), { name: 'health-check', interval: '30s' })
16
+ * .build((msg) => eventSocketManager.broadcastMessage(msg));
17
+ *
18
+ * app.use('/api/v1/qcli/jobs', jobsPlugin.router);
19
+ * await jobsPlugin.scheduler.start();
20
+ * ```
21
+ */
22
+ class CliJobsBuilder {
23
+ _jobs = [];
24
+ _storageProvider;
25
+ /**
26
+ * Register a job to be managed by the scheduler.
27
+ */
28
+ addJob(job, options) {
29
+ this._jobs.push({ job, options });
30
+ return this;
31
+ }
32
+ /**
33
+ * Set a custom storage provider for job state and execution history.
34
+ * If not set, an in-memory provider will be used.
35
+ */
36
+ setStorageProvider(provider) {
37
+ this._storageProvider = provider;
38
+ return this;
39
+ }
40
+ /**
41
+ * Build the plugin, returning the Express router and scheduler.
42
+ *
43
+ * @param broadcastFn Optional function to broadcast job events (e.g. via WebSocket).
44
+ */
45
+ build(broadcastFn) {
46
+ const storage = this._storageProvider ?? new in_memory_job_storage_provider_1.InMemoryJobStorageProvider();
47
+ const scheduler = new cli_job_scheduler_1.CliJobScheduler(storage);
48
+ for (const { job, options } of this._jobs) {
49
+ scheduler.register(job, options);
50
+ }
51
+ if (broadcastFn) {
52
+ scheduler.setBroadcastFn(broadcastFn);
53
+ }
54
+ const router = (0, cli_jobs_controller_1.createCliJobsController)(scheduler, storage);
55
+ return { prefix: '/api/v1/qcli/jobs', router, scheduler };
56
+ }
57
+ }
58
+ exports.CliJobsBuilder = CliJobsBuilder;
59
+ //# sourceMappingURL=cli-jobs-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-jobs-builder.js","sourceRoot":"","sources":["../cli-jobs-builder.ts"],"names":[],"mappings":";;;AAEA,2DAAsD;AACtD,qFAA8E;AAC9E,+DAAgE;AAWhE;;;;;;;;;;;;;;GAcG;AACH,MAAa,cAAc;IACN,KAAK,GAAoD,EAAE,CAAC;IACrE,gBAAgB,CAA0B;IAElD;;OAEG;IACH,MAAM,CAAC,GAAY,EAAE,OAAsB;QACvC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,kBAAkB,CAAC,QAAgC;QAC/C,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC;QACjC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAwD;QAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,IAAI,IAAI,2DAA0B,EAAE,CAAC;QAC1E,MAAM,SAAS,GAAG,IAAI,mCAAe,CAAC,OAAO,CAAC,CAAC;QAE/C,KAAK,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACxC,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,WAAW,EAAE,CAAC;YACd,SAAS,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;QAC1C,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,6CAAuB,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAE3D,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC9D,CAAC;CACJ;AA1CD,wCA0CC"}
@@ -0,0 +1,24 @@
1
+ import { Router } from 'express';
2
+ import { CliJobScheduler } from './cli-job-scheduler';
3
+ import { ICliJobStorageProvider } from '@qodalis/cli-server-abstractions';
4
+ /**
5
+ * Creates the jobs REST controller router.
6
+ *
7
+ * Routes (relative to mount point):
8
+ * - GET / - list all jobs
9
+ * - GET /:id - single job details
10
+ * - POST /:id/trigger - trigger immediate execution
11
+ * - POST /:id/pause - pause scheduled execution
12
+ * - POST /:id/resume - resume a paused job
13
+ * - POST /:id/stop - stop job and cancel if running
14
+ * - POST /:id/cancel - cancel current execution only
15
+ * - PUT /:id - update job options
16
+ * - GET /:id/history - paginated execution history
17
+ * - GET /:id/history/:execId - single execution with full logs
18
+ *
19
+ * @param scheduler - The job scheduler managing registrations and execution.
20
+ * @param storage - Storage provider for execution history lookups.
21
+ * @returns An Express router.
22
+ */
23
+ export declare function createCliJobsController(scheduler: CliJobScheduler, storage: ICliJobStorageProvider): Router;
24
+ //# sourceMappingURL=cli-jobs-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-jobs-controller.d.ts","sourceRoot":"","sources":["../cli-jobs-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,eAAe,EAAY,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAsB,MAAM,kCAAkC,CAAC;AAE9F;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CACnC,SAAS,EAAE,eAAe,EAC1B,OAAO,EAAE,sBAAsB,GAChC,MAAM,CA2HR"}