@gravito/horizon 3.2.2 → 4.0.0

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.cjs CHANGED
@@ -7820,6 +7820,35 @@ __export(index_exports, {
7820
7820
  });
7821
7821
  module.exports = __toCommonJS(index_exports);
7822
7822
 
7823
+ // src/errors/HorizonError.ts
7824
+ var import_core = require("@gravito/core");
7825
+ var HorizonError = class extends import_core.SystemException {
7826
+ constructor(status, code, options = {}) {
7827
+ super(status, code, options);
7828
+ this.name = "HorizonError";
7829
+ Object.setPrototypeOf(this, new.target.prototype);
7830
+ }
7831
+ };
7832
+
7833
+ // src/errors/codes.ts
7834
+ var HorizonErrorCodes = {
7835
+ // Scheduling errors
7836
+ CRON_PARSE_ERROR: "horizon.cron_parse_error",
7837
+ SCHEDULE_FAILED: "horizon.schedule_failed",
7838
+ COMMAND_FAILED: "horizon.command_failed",
7839
+ // Validation errors
7840
+ INVALID_TIME_FORMAT: "horizon.invalid_time_format",
7841
+ INVALID_MINUTE: "horizon.invalid_minute",
7842
+ INVALID_DAY_OF_WEEK: "horizon.invalid_day_of_week",
7843
+ INVALID_DAY_OF_MONTH: "horizon.invalid_day_of_month",
7844
+ INVALID_TIMEOUT: "horizon.invalid_timeout",
7845
+ INVALID_RETRY_ATTEMPTS: "horizon.invalid_retry_attempts",
7846
+ INVALID_RETRY_DELAY: "horizon.invalid_retry_delay",
7847
+ INVALID_TIMEZONE: "horizon.invalid_timezone",
7848
+ // Lock errors
7849
+ LOCK_DRIVER_REQUIRED: "horizon.lock_driver_required"
7850
+ };
7851
+
7823
7852
  // src/SimpleCronParser.ts
7824
7853
  var SimpleCronParser = class {
7825
7854
  /**
@@ -7839,7 +7868,9 @@ var SimpleCronParser = class {
7839
7868
  static isDue(expression, timezone = "UTC", date = /* @__PURE__ */ new Date()) {
7840
7869
  const parts = expression.trim().split(/\s+/);
7841
7870
  if (parts.length !== 5) {
7842
- throw new Error(`Invalid cron expression: ${expression}`);
7871
+ throw new HorizonError(422, HorizonErrorCodes.CRON_PARSE_ERROR, {
7872
+ message: `Invalid cron expression: ${expression}`
7873
+ });
7843
7874
  }
7844
7875
  const targetDate = this.getDateInTimezone(date, timezone);
7845
7876
  const minutes = targetDate.getMinutes();
@@ -7902,11 +7933,16 @@ var SimpleCronParser = class {
7902
7933
  try {
7903
7934
  const tzDate = new Date(date.toLocaleString("en-US", { timeZone: timezone }));
7904
7935
  if (Number.isNaN(tzDate.getTime())) {
7905
- throw new Error();
7936
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIMEZONE, {
7937
+ message: `Invalid timezone: ${timezone}`
7938
+ });
7906
7939
  }
7907
7940
  return tzDate;
7908
- } catch {
7909
- throw new Error(`Invalid timezone: ${timezone}`);
7941
+ } catch (err) {
7942
+ if (err instanceof HorizonError) throw err;
7943
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIMEZONE, {
7944
+ message: `Invalid timezone: ${timezone}`
7945
+ });
7910
7946
  }
7911
7947
  }
7912
7948
  };
@@ -7943,7 +7979,9 @@ var CronParser = class {
7943
7979
  });
7944
7980
  return interval.next().toDate();
7945
7981
  } catch (_err) {
7946
- throw new Error(`Invalid cron expression: ${expression}`);
7982
+ throw new HorizonError(422, HorizonErrorCodes.CRON_PARSE_ERROR, {
7983
+ message: `Invalid cron expression: ${expression}`
7984
+ });
7947
7985
  }
7948
7986
  }
7949
7987
  /**
@@ -8166,7 +8204,9 @@ var LockManager = class {
8166
8204
  this.store = new MemoryLockStore();
8167
8205
  } else if (driver === "cache") {
8168
8206
  if (!context?.cache) {
8169
- throw new Error("CacheManager is required for cache lock driver");
8207
+ throw new HorizonError(422, HorizonErrorCodes.LOCK_DRIVER_REQUIRED, {
8208
+ message: "CacheManager is required for cache lock driver"
8209
+ });
8170
8210
  }
8171
8211
  this.store = new CacheLockStore(context.cache);
8172
8212
  } else {
@@ -8247,28 +8287,38 @@ function parseTime(time) {
8247
8287
  const timePattern = /^([0-2]\d):([0-5]\d)$/;
8248
8288
  const match = time.match(timePattern);
8249
8289
  if (!match) {
8250
- throw new Error(`Invalid time format: "${time}". Expected HH:mm (24-hour format, 00:00-23:59)`);
8290
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIME_FORMAT, {
8291
+ message: `Invalid time format: "${time}". Expected HH:mm (24-hour format, 00:00-23:59)`
8292
+ });
8251
8293
  }
8252
8294
  const hour = Number.parseInt(match[1], 10);
8253
8295
  const minute = Number.parseInt(match[2], 10);
8254
8296
  if (hour > 23) {
8255
- throw new Error(`Invalid time format: "${time}". Expected HH:mm (24-hour format, 00:00-23:59)`);
8297
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIME_FORMAT, {
8298
+ message: `Invalid time format: "${time}". Expected HH:mm (24-hour format, 00:00-23:59)`
8299
+ });
8256
8300
  }
8257
8301
  return { hour, minute };
8258
8302
  }
8259
8303
  function validateMinute(minute) {
8260
8304
  if (!Number.isInteger(minute) || minute < 0 || minute > 59) {
8261
- throw new Error(`Invalid minute: ${minute}. Expected integer 0-59`);
8305
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_MINUTE, {
8306
+ message: `Invalid minute: ${minute}. Expected integer 0-59`
8307
+ });
8262
8308
  }
8263
8309
  }
8264
8310
  function validateDayOfWeek(dayOfWeek) {
8265
8311
  if (!Number.isInteger(dayOfWeek) || dayOfWeek < 0 || dayOfWeek > 6) {
8266
- throw new Error(`Invalid day of week: ${dayOfWeek}. Expected 0-6 (Sunday=0, Saturday=6)`);
8312
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_DAY_OF_WEEK, {
8313
+ message: `Invalid day of week: ${dayOfWeek}. Expected 0-6 (Sunday=0, Saturday=6)`
8314
+ });
8267
8315
  }
8268
8316
  }
8269
8317
  function validateDayOfMonth(dayOfMonth) {
8270
8318
  if (!Number.isInteger(dayOfMonth) || dayOfMonth < 1 || dayOfMonth > 31) {
8271
- throw new Error(`Invalid day of month: ${dayOfMonth}. Expected 1-31`);
8319
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_DAY_OF_MONTH, {
8320
+ message: `Invalid day of month: ${dayOfMonth}. Expected 1-31`
8321
+ });
8272
8322
  }
8273
8323
  }
8274
8324
 
@@ -8316,16 +8366,16 @@ var TaskSchedule = class {
8316
8366
  cron(expression) {
8317
8367
  const parts = expression.trim().split(/\s+/);
8318
8368
  if (parts.length !== 5) {
8319
- throw new Error(
8320
- `Invalid cron expression: "${expression}". Expected 5 parts (minute hour day month weekday), got ${parts.length}.`
8321
- );
8369
+ throw new HorizonError(422, HorizonErrorCodes.CRON_PARSE_ERROR, {
8370
+ message: `Invalid cron expression: "${expression}". Expected 5 parts (minute hour day month weekday), got ${parts.length}.`
8371
+ });
8322
8372
  }
8323
8373
  const pattern = /^[0-9,\-/*?L#A-Za-z]+$/;
8324
8374
  for (let i = 0; i < 5; i++) {
8325
8375
  if (!pattern.test(parts[i])) {
8326
- throw new Error(
8327
- `Invalid cron expression: "${expression}". Part ${i + 1} ("${parts[i]}") contains invalid characters.`
8328
- );
8376
+ throw new HorizonError(422, HorizonErrorCodes.CRON_PARSE_ERROR, {
8377
+ message: `Invalid cron expression: "${expression}". Part ${i + 1} ("${parts[i]}") contains invalid characters.`
8378
+ });
8329
8379
  }
8330
8380
  }
8331
8381
  this.task.expression = expression;
@@ -8473,9 +8523,9 @@ var TaskSchedule = class {
8473
8523
  try {
8474
8524
  (/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: timezone });
8475
8525
  } catch {
8476
- throw new Error(
8477
- `Invalid timezone: "${timezone}". See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for valid values.`
8478
- );
8526
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIMEZONE, {
8527
+ message: `Invalid timezone: "${timezone}". See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for valid values.`
8528
+ });
8479
8529
  }
8480
8530
  this.task.timezone = timezone;
8481
8531
  return this;
@@ -8561,7 +8611,9 @@ var TaskSchedule = class {
8561
8611
  */
8562
8612
  timeout(ms) {
8563
8613
  if (ms <= 0) {
8564
- throw new Error("Timeout must be a positive number");
8614
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIMEOUT, {
8615
+ message: "Timeout must be a positive number"
8616
+ });
8565
8617
  }
8566
8618
  this.task.timeout = ms;
8567
8619
  return this;
@@ -8576,10 +8628,14 @@ var TaskSchedule = class {
8576
8628
  */
8577
8629
  retry(attempts = 3, delayMs = 1e3) {
8578
8630
  if (attempts < 0) {
8579
- throw new Error("Retry attempts must be non-negative");
8631
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_RETRY_ATTEMPTS, {
8632
+ message: "Retry attempts must be non-negative"
8633
+ });
8580
8634
  }
8581
8635
  if (delayMs < 0) {
8582
- throw new Error("Retry delay must be non-negative");
8636
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_RETRY_DELAY, {
8637
+ message: "Retry delay must be non-negative"
8638
+ });
8583
8639
  }
8584
8640
  this.task.retries = attempts;
8585
8641
  this.task.retryDelay = delayMs;
@@ -8694,7 +8750,9 @@ var SchedulerManager = class {
8694
8750
  const task = new TaskSchedule(name, async () => {
8695
8751
  const result = await Process.run(command);
8696
8752
  if (!result.success) {
8697
- throw new Error(`Command failed: ${result.stderr || result.stdout}`);
8753
+ throw new HorizonError(500, HorizonErrorCodes.COMMAND_FAILED, {
8754
+ message: `Command failed: ${result.stderr || result.stdout}`
8755
+ });
8698
8756
  }
8699
8757
  });
8700
8758
  task.setCommand(command);
package/dist/index.js CHANGED
@@ -1,5 +1,34 @@
1
1
  import "./chunk-MCKGQKYU.js";
2
2
 
3
+ // src/errors/HorizonError.ts
4
+ import { SystemException } from "@gravito/core";
5
+ var HorizonError = class extends SystemException {
6
+ constructor(status, code, options = {}) {
7
+ super(status, code, options);
8
+ this.name = "HorizonError";
9
+ Object.setPrototypeOf(this, new.target.prototype);
10
+ }
11
+ };
12
+
13
+ // src/errors/codes.ts
14
+ var HorizonErrorCodes = {
15
+ // Scheduling errors
16
+ CRON_PARSE_ERROR: "horizon.cron_parse_error",
17
+ SCHEDULE_FAILED: "horizon.schedule_failed",
18
+ COMMAND_FAILED: "horizon.command_failed",
19
+ // Validation errors
20
+ INVALID_TIME_FORMAT: "horizon.invalid_time_format",
21
+ INVALID_MINUTE: "horizon.invalid_minute",
22
+ INVALID_DAY_OF_WEEK: "horizon.invalid_day_of_week",
23
+ INVALID_DAY_OF_MONTH: "horizon.invalid_day_of_month",
24
+ INVALID_TIMEOUT: "horizon.invalid_timeout",
25
+ INVALID_RETRY_ATTEMPTS: "horizon.invalid_retry_attempts",
26
+ INVALID_RETRY_DELAY: "horizon.invalid_retry_delay",
27
+ INVALID_TIMEZONE: "horizon.invalid_timezone",
28
+ // Lock errors
29
+ LOCK_DRIVER_REQUIRED: "horizon.lock_driver_required"
30
+ };
31
+
3
32
  // src/SimpleCronParser.ts
4
33
  var SimpleCronParser = class {
5
34
  /**
@@ -19,7 +48,9 @@ var SimpleCronParser = class {
19
48
  static isDue(expression, timezone = "UTC", date = /* @__PURE__ */ new Date()) {
20
49
  const parts = expression.trim().split(/\s+/);
21
50
  if (parts.length !== 5) {
22
- throw new Error(`Invalid cron expression: ${expression}`);
51
+ throw new HorizonError(422, HorizonErrorCodes.CRON_PARSE_ERROR, {
52
+ message: `Invalid cron expression: ${expression}`
53
+ });
23
54
  }
24
55
  const targetDate = this.getDateInTimezone(date, timezone);
25
56
  const minutes = targetDate.getMinutes();
@@ -82,11 +113,16 @@ var SimpleCronParser = class {
82
113
  try {
83
114
  const tzDate = new Date(date.toLocaleString("en-US", { timeZone: timezone }));
84
115
  if (Number.isNaN(tzDate.getTime())) {
85
- throw new Error();
116
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIMEZONE, {
117
+ message: `Invalid timezone: ${timezone}`
118
+ });
86
119
  }
87
120
  return tzDate;
88
- } catch {
89
- throw new Error(`Invalid timezone: ${timezone}`);
121
+ } catch (err) {
122
+ if (err instanceof HorizonError) throw err;
123
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIMEZONE, {
124
+ message: `Invalid timezone: ${timezone}`
125
+ });
90
126
  }
91
127
  }
92
128
  };
@@ -123,7 +159,9 @@ var CronParser = class {
123
159
  });
124
160
  return interval.next().toDate();
125
161
  } catch (_err) {
126
- throw new Error(`Invalid cron expression: ${expression}`);
162
+ throw new HorizonError(422, HorizonErrorCodes.CRON_PARSE_ERROR, {
163
+ message: `Invalid cron expression: ${expression}`
164
+ });
127
165
  }
128
166
  }
129
167
  /**
@@ -346,7 +384,9 @@ var LockManager = class {
346
384
  this.store = new MemoryLockStore();
347
385
  } else if (driver === "cache") {
348
386
  if (!context?.cache) {
349
- throw new Error("CacheManager is required for cache lock driver");
387
+ throw new HorizonError(422, HorizonErrorCodes.LOCK_DRIVER_REQUIRED, {
388
+ message: "CacheManager is required for cache lock driver"
389
+ });
350
390
  }
351
391
  this.store = new CacheLockStore(context.cache);
352
392
  } else {
@@ -427,28 +467,38 @@ function parseTime(time) {
427
467
  const timePattern = /^([0-2]\d):([0-5]\d)$/;
428
468
  const match = time.match(timePattern);
429
469
  if (!match) {
430
- throw new Error(`Invalid time format: "${time}". Expected HH:mm (24-hour format, 00:00-23:59)`);
470
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIME_FORMAT, {
471
+ message: `Invalid time format: "${time}". Expected HH:mm (24-hour format, 00:00-23:59)`
472
+ });
431
473
  }
432
474
  const hour = Number.parseInt(match[1], 10);
433
475
  const minute = Number.parseInt(match[2], 10);
434
476
  if (hour > 23) {
435
- throw new Error(`Invalid time format: "${time}". Expected HH:mm (24-hour format, 00:00-23:59)`);
477
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIME_FORMAT, {
478
+ message: `Invalid time format: "${time}". Expected HH:mm (24-hour format, 00:00-23:59)`
479
+ });
436
480
  }
437
481
  return { hour, minute };
438
482
  }
439
483
  function validateMinute(minute) {
440
484
  if (!Number.isInteger(minute) || minute < 0 || minute > 59) {
441
- throw new Error(`Invalid minute: ${minute}. Expected integer 0-59`);
485
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_MINUTE, {
486
+ message: `Invalid minute: ${minute}. Expected integer 0-59`
487
+ });
442
488
  }
443
489
  }
444
490
  function validateDayOfWeek(dayOfWeek) {
445
491
  if (!Number.isInteger(dayOfWeek) || dayOfWeek < 0 || dayOfWeek > 6) {
446
- throw new Error(`Invalid day of week: ${dayOfWeek}. Expected 0-6 (Sunday=0, Saturday=6)`);
492
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_DAY_OF_WEEK, {
493
+ message: `Invalid day of week: ${dayOfWeek}. Expected 0-6 (Sunday=0, Saturday=6)`
494
+ });
447
495
  }
448
496
  }
449
497
  function validateDayOfMonth(dayOfMonth) {
450
498
  if (!Number.isInteger(dayOfMonth) || dayOfMonth < 1 || dayOfMonth > 31) {
451
- throw new Error(`Invalid day of month: ${dayOfMonth}. Expected 1-31`);
499
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_DAY_OF_MONTH, {
500
+ message: `Invalid day of month: ${dayOfMonth}. Expected 1-31`
501
+ });
452
502
  }
453
503
  }
454
504
 
@@ -496,16 +546,16 @@ var TaskSchedule = class {
496
546
  cron(expression) {
497
547
  const parts = expression.trim().split(/\s+/);
498
548
  if (parts.length !== 5) {
499
- throw new Error(
500
- `Invalid cron expression: "${expression}". Expected 5 parts (minute hour day month weekday), got ${parts.length}.`
501
- );
549
+ throw new HorizonError(422, HorizonErrorCodes.CRON_PARSE_ERROR, {
550
+ message: `Invalid cron expression: "${expression}". Expected 5 parts (minute hour day month weekday), got ${parts.length}.`
551
+ });
502
552
  }
503
553
  const pattern = /^[0-9,\-/*?L#A-Za-z]+$/;
504
554
  for (let i = 0; i < 5; i++) {
505
555
  if (!pattern.test(parts[i])) {
506
- throw new Error(
507
- `Invalid cron expression: "${expression}". Part ${i + 1} ("${parts[i]}") contains invalid characters.`
508
- );
556
+ throw new HorizonError(422, HorizonErrorCodes.CRON_PARSE_ERROR, {
557
+ message: `Invalid cron expression: "${expression}". Part ${i + 1} ("${parts[i]}") contains invalid characters.`
558
+ });
509
559
  }
510
560
  }
511
561
  this.task.expression = expression;
@@ -653,9 +703,9 @@ var TaskSchedule = class {
653
703
  try {
654
704
  (/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: timezone });
655
705
  } catch {
656
- throw new Error(
657
- `Invalid timezone: "${timezone}". See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for valid values.`
658
- );
706
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIMEZONE, {
707
+ message: `Invalid timezone: "${timezone}". See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for valid values.`
708
+ });
659
709
  }
660
710
  this.task.timezone = timezone;
661
711
  return this;
@@ -741,7 +791,9 @@ var TaskSchedule = class {
741
791
  */
742
792
  timeout(ms) {
743
793
  if (ms <= 0) {
744
- throw new Error("Timeout must be a positive number");
794
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_TIMEOUT, {
795
+ message: "Timeout must be a positive number"
796
+ });
745
797
  }
746
798
  this.task.timeout = ms;
747
799
  return this;
@@ -756,10 +808,14 @@ var TaskSchedule = class {
756
808
  */
757
809
  retry(attempts = 3, delayMs = 1e3) {
758
810
  if (attempts < 0) {
759
- throw new Error("Retry attempts must be non-negative");
811
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_RETRY_ATTEMPTS, {
812
+ message: "Retry attempts must be non-negative"
813
+ });
760
814
  }
761
815
  if (delayMs < 0) {
762
- throw new Error("Retry delay must be non-negative");
816
+ throw new HorizonError(422, HorizonErrorCodes.INVALID_RETRY_DELAY, {
817
+ message: "Retry delay must be non-negative"
818
+ });
763
819
  }
764
820
  this.task.retries = attempts;
765
821
  this.task.retryDelay = delayMs;
@@ -874,7 +930,9 @@ var SchedulerManager = class {
874
930
  const task = new TaskSchedule(name, async () => {
875
931
  const result = await Process.run(command);
876
932
  if (!result.success) {
877
- throw new Error(`Command failed: ${result.stderr || result.stdout}`);
933
+ throw new HorizonError(500, HorizonErrorCodes.COMMAND_FAILED, {
934
+ message: `Command failed: ${result.stderr || result.stdout}`
935
+ });
878
936
  }
879
937
  });
880
938
  task.setCommand(command);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gravito/horizon",
3
3
  "sideEffects": false,
4
- "version": "3.2.2",
4
+ "version": "4.0.0",
5
5
  "description": "Distributed task scheduler for Gravito framework",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -46,8 +46,8 @@
46
46
  "cron-parser": "^4.9.0"
47
47
  },
48
48
  "peerDependencies": {
49
- "@gravito/core": "^2.0.0",
50
- "@gravito/stasis": "^3.2.0"
49
+ "@gravito/core": "^3.0.0",
50
+ "@gravito/stasis": "^4.0.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@gravito/stasis": "workspace:*",