@freshpointcz/fresh-core 0.0.12 → 0.0.14

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/dist/index.d.mts CHANGED
@@ -58,10 +58,62 @@ declare const logger: Logger;
58
58
 
59
59
  declare function isValidCron(expr: string): boolean;
60
60
 
61
+ /**
62
+ * Abstract base class implementing a per-subclass Singleton pattern.
63
+ *
64
+ * Each subclass of `Singleton` can have exactly one instance.
65
+ * Instantiation is guarded at runtime: calling `new` multiple times
66
+ * will always return the first created instance for that subclass.
67
+ *
68
+ * Instances are stored internally in a static map keyed by constructor
69
+ * function, allowing independent singleton instances per subclass.
70
+ *
71
+ * ⚠️ Important:
72
+ * - Subclasses MUST NOT override the constructor unless they fully
73
+ * understand the consequences.
74
+ * - Initialization logic must be placed in {@link onInit}, not the constructor.
75
+ * - The constructor may return an existing instance, which is legal in JS
76
+ * but mildly unsettling.
77
+ */
61
78
  declare abstract class Singleton {
79
+ /**
80
+ * Internal registry of singleton instances.
81
+ * One instance per subclass constructor.
82
+ */
62
83
  private static instances;
63
- constructor();
64
- protected abstract onInit(): void;
84
+ /**
85
+ * Creates or returns the singleton instance for the subclass.
86
+ *
87
+ * If an instance already exists for the subclass, that instance is
88
+ * returned instead of creating a new one.
89
+ *
90
+ * @param callOnInit - Whether to call {@link onInit} for a newly
91
+ * created instance. Ignored if the instance already exists.
92
+ */
93
+ constructor(callOnInit?: boolean);
94
+ /**
95
+ * Retrieves the singleton instance for the calling subclass.
96
+ *
97
+ * If no instance exists, a new one is created using the provided
98
+ * constructor arguments.
99
+ *
100
+ * Intended to be used by subclasses as a protected factory method.
101
+ *
102
+ * @typeParam T - The concrete subclass type.
103
+ * @param args - Arguments forwarded to the subclass constructor.
104
+ * @returns The singleton instance of the subclass.
105
+ */
106
+ protected static getInstance<T>(this: new (...args: any[]) => T, ...args: ConstructorParameters<any>): T;
107
+ /**
108
+ * Lifecycle hook called once when the singleton instance is first created.
109
+ *
110
+ * Subclasses must implement this method instead of relying on the
111
+ * constructor for initialization logic.
112
+ *
113
+ * This method is guaranteed to be called at most once per subclass
114
+ * instance.
115
+ */
116
+ protected abstract onInit(): void | Promise<void>;
65
117
  }
66
118
 
67
119
  type Status = "ok" | "error" | "not-authorized" | "not-authenticated" | "internal-server-error" | "validation-error";
@@ -323,23 +375,93 @@ declare abstract class DataHelper<T> {
323
375
  abstract startDataRetrieval(): Promise<Maybe<T>>;
324
376
  }
325
377
 
378
+ /**
379
+ * Abstract base class for scheduled singleton jobs.
380
+ *
381
+ * Combines:
382
+ * - a per-subclass Singleton lifecycle
383
+ * - cron-based scheduling via `node-schedule`
384
+ * - a predictable execution entry point via {@link invoke}
385
+ *
386
+ * Each concrete job:
387
+ * - exists exactly once per process
388
+ * - may or may not be scheduled (depending on `jobEnabled`)
389
+ * - is responsible only for business logic, not scheduling mechanics
390
+ *
391
+ * The job is scheduled immediately during construction if enabled.
392
+ * Initialization logging is handled internally.
393
+ *
394
+ * @typeParam T - Return type of the job execution.
395
+ *
396
+ * ⚠️ Design notes for future maintainers:
397
+ * - Do NOT override the constructor unless you enjoy debugging time-based bugs.
398
+ * - All job logic belongs in {@link invoke}.
399
+ * - Rescheduling requires calling {@link reschedule} with valid cron.
400
+ */
326
401
  declare abstract class FreshJob<T = void> extends Singleton {
402
+ /** Human-readable job identifier (used for logs and errors). */
327
403
  private _jobName;
404
+ /**
405
+ * Cron expression defining when the job runs.
406
+ *
407
+ * Must contain numeric cron fields only.
408
+ * Example: `0 5 * * 4`
409
+ *
410
+ * Timezone is always forced to `"Europe/Prague"`.
411
+ * If you need another timezone, this class is not your friend.
412
+ */
328
413
  private _cronExpression;
414
+ /** Scheduled job instance, or `null` if the job is disabled. */
329
415
  private _job;
330
416
  /**
331
- * @param cronExpression must be cron of just numbers ex.: `0 5 * * 4`
332
- * By default timezone is added " Europe/Prague"
417
+ * Creates and optionally schedules a singleton cron job.
418
+ *
419
+ * @param jobName - Logical name of the job (used in logs and errors).
420
+ * @param cronExpression - Cron expression consisting of numeric fields only.
421
+ * Example: `0 5 * * 4`
422
+ * The timezone `"Europe/Prague"` is applied automatically.
423
+ *
424
+ * @param jobEnabled - Whether the job should be scheduled immediately.
425
+ * If `false`, the instance exists but no cron trigger is registered.
426
+ *
427
+ * @throws Error If the cron expression is invalid.
428
+ * @throws Error If the job cannot be scheduled.
333
429
  */
334
430
  constructor(jobName: string, cronExpression: string, jobEnabled: boolean);
335
- /** Just logging */
431
+ /**
432
+ * Initialization hook.
433
+ *
434
+ * Called once during construction and used primarily for logging.
435
+ * Can also be reused by subclasses if manual rescheduling is implemented.
436
+ *
437
+ * @param rescheduled - Indicates whether the job was reconfigured
438
+ * after initial creation.
439
+ */
336
440
  protected onInit(rescheduled?: boolean): void;
441
+ /** @returns The logical name of the job. */
337
442
  get jobName(): string;
443
+ /** Allows subclasses to rename the job if absolutely necessary. */
338
444
  protected set jobName(value: string);
445
+ /** @returns The cron expression used to schedule the job. */
339
446
  get cronExpression(): string;
447
+ /**
448
+ * Allows subclasses to update the cron expression internally.
449
+ * Does reschedule of job if exists
450
+ */
340
451
  protected set cronExpression(value: string);
452
+ /** @returns The underlying scheduled job instance, or `null` if disabled. */
341
453
  protected get job(): Job | null;
454
+ /** Allows subclasses to manage the scheduled job instance. */
342
455
  protected set job(value: Job | null);
456
+ protected reschedule(newCronExpression: string): boolean;
457
+ /**
458
+ * Job execution entry point.
459
+ *
460
+ * This method is called by the scheduler when the cron rule matches.
461
+ * All business logic belongs here.
462
+ *
463
+ * @returns The result of the job execution, optionally wrapped in a Promise.
464
+ */
343
465
  abstract invoke(): T | Promise<T>;
344
466
  }
345
467
 
package/dist/index.d.ts CHANGED
@@ -58,10 +58,62 @@ declare const logger: Logger;
58
58
 
59
59
  declare function isValidCron(expr: string): boolean;
60
60
 
61
+ /**
62
+ * Abstract base class implementing a per-subclass Singleton pattern.
63
+ *
64
+ * Each subclass of `Singleton` can have exactly one instance.
65
+ * Instantiation is guarded at runtime: calling `new` multiple times
66
+ * will always return the first created instance for that subclass.
67
+ *
68
+ * Instances are stored internally in a static map keyed by constructor
69
+ * function, allowing independent singleton instances per subclass.
70
+ *
71
+ * ⚠️ Important:
72
+ * - Subclasses MUST NOT override the constructor unless they fully
73
+ * understand the consequences.
74
+ * - Initialization logic must be placed in {@link onInit}, not the constructor.
75
+ * - The constructor may return an existing instance, which is legal in JS
76
+ * but mildly unsettling.
77
+ */
61
78
  declare abstract class Singleton {
79
+ /**
80
+ * Internal registry of singleton instances.
81
+ * One instance per subclass constructor.
82
+ */
62
83
  private static instances;
63
- constructor();
64
- protected abstract onInit(): void;
84
+ /**
85
+ * Creates or returns the singleton instance for the subclass.
86
+ *
87
+ * If an instance already exists for the subclass, that instance is
88
+ * returned instead of creating a new one.
89
+ *
90
+ * @param callOnInit - Whether to call {@link onInit} for a newly
91
+ * created instance. Ignored if the instance already exists.
92
+ */
93
+ constructor(callOnInit?: boolean);
94
+ /**
95
+ * Retrieves the singleton instance for the calling subclass.
96
+ *
97
+ * If no instance exists, a new one is created using the provided
98
+ * constructor arguments.
99
+ *
100
+ * Intended to be used by subclasses as a protected factory method.
101
+ *
102
+ * @typeParam T - The concrete subclass type.
103
+ * @param args - Arguments forwarded to the subclass constructor.
104
+ * @returns The singleton instance of the subclass.
105
+ */
106
+ protected static getInstance<T>(this: new (...args: any[]) => T, ...args: ConstructorParameters<any>): T;
107
+ /**
108
+ * Lifecycle hook called once when the singleton instance is first created.
109
+ *
110
+ * Subclasses must implement this method instead of relying on the
111
+ * constructor for initialization logic.
112
+ *
113
+ * This method is guaranteed to be called at most once per subclass
114
+ * instance.
115
+ */
116
+ protected abstract onInit(): void | Promise<void>;
65
117
  }
66
118
 
67
119
  type Status = "ok" | "error" | "not-authorized" | "not-authenticated" | "internal-server-error" | "validation-error";
@@ -323,23 +375,93 @@ declare abstract class DataHelper<T> {
323
375
  abstract startDataRetrieval(): Promise<Maybe<T>>;
324
376
  }
325
377
 
378
+ /**
379
+ * Abstract base class for scheduled singleton jobs.
380
+ *
381
+ * Combines:
382
+ * - a per-subclass Singleton lifecycle
383
+ * - cron-based scheduling via `node-schedule`
384
+ * - a predictable execution entry point via {@link invoke}
385
+ *
386
+ * Each concrete job:
387
+ * - exists exactly once per process
388
+ * - may or may not be scheduled (depending on `jobEnabled`)
389
+ * - is responsible only for business logic, not scheduling mechanics
390
+ *
391
+ * The job is scheduled immediately during construction if enabled.
392
+ * Initialization logging is handled internally.
393
+ *
394
+ * @typeParam T - Return type of the job execution.
395
+ *
396
+ * ⚠️ Design notes for future maintainers:
397
+ * - Do NOT override the constructor unless you enjoy debugging time-based bugs.
398
+ * - All job logic belongs in {@link invoke}.
399
+ * - Rescheduling requires calling {@link reschedule} with valid cron.
400
+ */
326
401
  declare abstract class FreshJob<T = void> extends Singleton {
402
+ /** Human-readable job identifier (used for logs and errors). */
327
403
  private _jobName;
404
+ /**
405
+ * Cron expression defining when the job runs.
406
+ *
407
+ * Must contain numeric cron fields only.
408
+ * Example: `0 5 * * 4`
409
+ *
410
+ * Timezone is always forced to `"Europe/Prague"`.
411
+ * If you need another timezone, this class is not your friend.
412
+ */
328
413
  private _cronExpression;
414
+ /** Scheduled job instance, or `null` if the job is disabled. */
329
415
  private _job;
330
416
  /**
331
- * @param cronExpression must be cron of just numbers ex.: `0 5 * * 4`
332
- * By default timezone is added " Europe/Prague"
417
+ * Creates and optionally schedules a singleton cron job.
418
+ *
419
+ * @param jobName - Logical name of the job (used in logs and errors).
420
+ * @param cronExpression - Cron expression consisting of numeric fields only.
421
+ * Example: `0 5 * * 4`
422
+ * The timezone `"Europe/Prague"` is applied automatically.
423
+ *
424
+ * @param jobEnabled - Whether the job should be scheduled immediately.
425
+ * If `false`, the instance exists but no cron trigger is registered.
426
+ *
427
+ * @throws Error If the cron expression is invalid.
428
+ * @throws Error If the job cannot be scheduled.
333
429
  */
334
430
  constructor(jobName: string, cronExpression: string, jobEnabled: boolean);
335
- /** Just logging */
431
+ /**
432
+ * Initialization hook.
433
+ *
434
+ * Called once during construction and used primarily for logging.
435
+ * Can also be reused by subclasses if manual rescheduling is implemented.
436
+ *
437
+ * @param rescheduled - Indicates whether the job was reconfigured
438
+ * after initial creation.
439
+ */
336
440
  protected onInit(rescheduled?: boolean): void;
441
+ /** @returns The logical name of the job. */
337
442
  get jobName(): string;
443
+ /** Allows subclasses to rename the job if absolutely necessary. */
338
444
  protected set jobName(value: string);
445
+ /** @returns The cron expression used to schedule the job. */
339
446
  get cronExpression(): string;
447
+ /**
448
+ * Allows subclasses to update the cron expression internally.
449
+ * Does reschedule of job if exists
450
+ */
340
451
  protected set cronExpression(value: string);
452
+ /** @returns The underlying scheduled job instance, or `null` if disabled. */
341
453
  protected get job(): Job | null;
454
+ /** Allows subclasses to manage the scheduled job instance. */
342
455
  protected set job(value: Job | null);
456
+ protected reschedule(newCronExpression: string): boolean;
457
+ /**
458
+ * Job execution entry point.
459
+ *
460
+ * This method is called by the scheduler when the cron rule matches.
461
+ * All business logic belongs here.
462
+ *
463
+ * @returns The result of the job execution, optionally wrapped in a Promise.
464
+ */
343
465
  abstract invoke(): T | Promise<T>;
344
466
  }
345
467