@velajs/vela 0.10.0 → 1.1.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.
Files changed (91) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/README.md +36 -2
  3. package/dist/cache/cache.decorators.d.ts +2 -2
  4. package/dist/cache/cache.module.d.ts +1 -1
  5. package/dist/cache/cache.module.js +1 -1
  6. package/dist/constants.d.ts +29 -26
  7. package/dist/constants.js +26 -29
  8. package/dist/container/container.js +2 -2
  9. package/dist/container/decorators.js +8 -11
  10. package/dist/container/types.d.ts +1 -0
  11. package/dist/errors/http-exception.d.ts +21 -20
  12. package/dist/errors/http-exception.js +6 -6
  13. package/dist/event-emitter/event-emitter.decorators.js +2 -3
  14. package/dist/event-emitter/event-emitter.subscriber.js +2 -1
  15. package/dist/factory.d.ts +0 -1
  16. package/dist/factory.js +2 -32
  17. package/dist/fetch/fetch.module.d.ts +2 -2
  18. package/dist/fetch/fetch.module.js +2 -2
  19. package/dist/health/health.service.js +6 -2
  20. package/dist/http/decorators.d.ts +6 -5
  21. package/dist/http/decorators.js +28 -76
  22. package/dist/http/execution-context.d.ts +4 -0
  23. package/dist/http/execution-context.js +15 -0
  24. package/dist/http/index.d.ts +2 -2
  25. package/dist/http/index.js +1 -1
  26. package/dist/http/route.manager.d.ts +1 -2
  27. package/dist/http/route.manager.js +20 -31
  28. package/dist/http/types.d.ts +0 -1
  29. package/dist/index.d.ts +4 -10
  30. package/dist/index.js +7 -12
  31. package/dist/internal.d.ts +11 -0
  32. package/dist/internal.js +13 -0
  33. package/dist/metadata.js +6 -15
  34. package/dist/module/decorators.d.ts +1 -3
  35. package/dist/module/decorators.js +8 -20
  36. package/dist/module/graph.d.ts +10 -0
  37. package/dist/module/graph.js +35 -0
  38. package/dist/module/index.d.ts +2 -0
  39. package/dist/module/index.js +1 -0
  40. package/dist/{http/middleware-consumer.d.ts → module/middleware.d.ts} +4 -13
  41. package/dist/{http/middleware-consumer.js → module/middleware.js} +0 -13
  42. package/dist/module/module-loader.d.ts +1 -1
  43. package/dist/module/module-loader.js +17 -13
  44. package/dist/module/types.d.ts +1 -29
  45. package/dist/openapi/decorators.js +15 -10
  46. package/dist/openapi/document.js +7 -42
  47. package/dist/pipeline/app-providers.d.ts +10 -0
  48. package/dist/pipeline/app-providers.js +43 -0
  49. package/dist/pipeline/component.manager.d.ts +1 -0
  50. package/dist/pipeline/component.manager.js +10 -34
  51. package/dist/pipeline/decorators.d.ts +5 -5
  52. package/dist/pipeline/decorators.js +1 -9
  53. package/dist/pipeline/reflector.d.ts +8 -24
  54. package/dist/pipeline/reflector.js +10 -55
  55. package/dist/registry/index.d.ts +1 -1
  56. package/dist/registry/metadata.registry.d.ts +20 -15
  57. package/dist/registry/metadata.registry.js +135 -154
  58. package/dist/registry/paths.d.ts +3 -0
  59. package/dist/registry/paths.js +15 -0
  60. package/dist/registry/types.d.ts +24 -14
  61. package/dist/registry/types.js +0 -1
  62. package/dist/registry/util.d.ts +3 -0
  63. package/dist/registry/util.js +8 -0
  64. package/dist/schedule/cron-matcher.d.ts +2 -0
  65. package/dist/schedule/cron-matcher.js +62 -0
  66. package/dist/schedule/index.d.ts +4 -3
  67. package/dist/schedule/index.js +2 -2
  68. package/dist/schedule/schedule.decorators.js +3 -6
  69. package/dist/schedule/schedule.module.d.ts +2 -6
  70. package/dist/schedule/schedule.module.js +4 -42
  71. package/dist/schedule/schedule.registry.js +3 -2
  72. package/dist/schedule/schedule.tokens.d.ts +0 -3
  73. package/dist/schedule/schedule.tokens.js +0 -2
  74. package/dist/schedule/schedule.types.d.ts +0 -3
  75. package/dist/schedule-node/index.d.ts +2 -0
  76. package/dist/schedule-node/index.js +2 -0
  77. package/dist/schedule-node/schedule-node.module.d.ts +4 -0
  78. package/dist/schedule-node/schedule-node.module.js +18 -0
  79. package/dist/{schedule → schedule-node}/schedule.executor.d.ts +2 -5
  80. package/dist/schedule-node/schedule.executor.js +91 -0
  81. package/dist/services/logger.d.ts +9 -8
  82. package/dist/services/logger.js +14 -15
  83. package/dist/throttler/throttler.decorators.d.ts +2 -2
  84. package/package.json +9 -9
  85. package/dist/schedule/schedule.executor.js +0 -169
  86. package/dist/testing/index.d.ts +0 -2
  87. package/dist/testing/index.js +0 -2
  88. package/dist/testing/testing.builder.d.ts +0 -29
  89. package/dist/testing/testing.builder.js +0 -148
  90. package/dist/testing/testing.module.d.ts +0 -9
  91. package/dist/testing/testing.module.js +0 -15
@@ -0,0 +1,2 @@
1
+ export type CronMatcher = (date: Date) => boolean;
2
+ export declare function parseCron(expression: string): CronMatcher | null;
@@ -0,0 +1,62 @@
1
+ export function parseCron(expression) {
2
+ const fields = expression.trim().split(/\s+/);
3
+ if (fields.length !== 5) return null;
4
+ const [minuteField, hourField, dayField, monthField, weekdayField] = fields;
5
+ const minute = parseField(minuteField, 0, 59);
6
+ const hour = parseField(hourField, 0, 23);
7
+ const day = parseField(dayField, 1, 31);
8
+ const month = parseField(monthField, 1, 12);
9
+ const weekday = parseField(weekdayField, 0, 7);
10
+ if (!minute || !hour || !day || !month || !weekday) return null;
11
+ return (date)=>minute(date.getMinutes()) && hour(date.getHours()) && day(date.getDate()) && month(date.getMonth() + 1) && weekday(date.getDay());
12
+ }
13
+ function parseField(field, min, max) {
14
+ const segments = field.split(',');
15
+ const predicates = [];
16
+ for (const rawSegment of segments){
17
+ const segment = rawSegment.trim();
18
+ if (!segment) return null;
19
+ const stepParts = segment.split('/');
20
+ if (stepParts.length > 2) return null;
21
+ const step = stepParts.length === 2 ? Number(stepParts[1]) : 1;
22
+ if (!Number.isInteger(step) || step <= 0) return null;
23
+ const range = parseRange(stepParts[0], min, max);
24
+ if (!range) return null;
25
+ predicates.push((value)=>{
26
+ if (value < range.start || value > range.end) return false;
27
+ return (value - range.start) % step === 0;
28
+ });
29
+ }
30
+ return (value)=>predicates.some((p)=>p(value));
31
+ }
32
+ function parseRange(segment, min, max) {
33
+ if (segment === '*') return {
34
+ start: min,
35
+ end: max
36
+ };
37
+ const bounds = segment.split('-');
38
+ if (bounds.length === 1) {
39
+ const value = parseCronNumber(bounds[0], min, max);
40
+ if (value === null) return null;
41
+ return {
42
+ start: value,
43
+ end: value
44
+ };
45
+ }
46
+ if (bounds.length !== 2) return null;
47
+ const start = parseCronNumber(bounds[0], min, max);
48
+ const end = parseCronNumber(bounds[1], min, max);
49
+ if (start === null || end === null || start > end) return null;
50
+ return {
51
+ start,
52
+ end
53
+ };
54
+ }
55
+ function parseCronNumber(raw, min, max) {
56
+ const value = Number(raw);
57
+ if (!Number.isInteger(value)) return null;
58
+ // Cron allows 0 and 7 as Sunday.
59
+ const normalized = max === 7 && value === 7 ? 0 : value;
60
+ if (normalized < min || normalized > max) return null;
61
+ return normalized;
62
+ }
@@ -1,7 +1,8 @@
1
1
  export { ScheduleModule } from './schedule.module';
2
2
  export { ScheduleRegistry } from './schedule.registry';
3
3
  export type { RegisteredCronJob, RegisteredIntervalJob } from './schedule.registry';
4
- export { ScheduleExecutor } from './schedule.executor';
5
4
  export { Cron, Interval } from './schedule.decorators';
6
- export { SCHEDULE_MODULE_OPTIONS, CRON_METADATA, INTERVAL_METADATA } from './schedule.tokens';
7
- export type { CronMetadata, IntervalMetadata, ScheduleModuleOptions } from './schedule.types';
5
+ export { CRON_METADATA, INTERVAL_METADATA } from './schedule.tokens';
6
+ export type { CronMetadata, IntervalMetadata } from './schedule.types';
7
+ export { parseCron } from './cron-matcher';
8
+ export type { CronMatcher } from './cron-matcher';
@@ -1,5 +1,5 @@
1
1
  export { ScheduleModule } from "./schedule.module.js";
2
2
  export { ScheduleRegistry } from "./schedule.registry.js";
3
- export { ScheduleExecutor } from "./schedule.executor.js";
4
3
  export { Cron, Interval } from "./schedule.decorators.js";
5
- export { SCHEDULE_MODULE_OPTIONS, CRON_METADATA, INTERVAL_METADATA } from "./schedule.tokens.js";
4
+ export { CRON_METADATA, INTERVAL_METADATA } from "./schedule.tokens.js";
5
+ export { parseCron } from "./cron-matcher.js";
@@ -1,21 +1,18 @@
1
+ import { MetadataRegistry } from "../registry/metadata.registry.js";
1
2
  import { CRON_METADATA, INTERVAL_METADATA } from "./schedule.tokens.js";
2
3
  export function Cron(expression) {
3
4
  return (target, propertyKey)=>{
4
- const existing = Reflect.getMetadata(CRON_METADATA, target.constructor) ?? [];
5
- existing.push({
5
+ MetadataRegistry.appendCustomClassMeta(target.constructor, CRON_METADATA, {
6
6
  expression,
7
7
  methodName: String(propertyKey)
8
8
  });
9
- Reflect.defineMetadata(CRON_METADATA, existing, target.constructor);
10
9
  };
11
10
  }
12
11
  export function Interval(ms) {
13
12
  return (target, propertyKey)=>{
14
- const existing = Reflect.getMetadata(INTERVAL_METADATA, target.constructor) ?? [];
15
- existing.push({
13
+ MetadataRegistry.appendCustomClassMeta(target.constructor, INTERVAL_METADATA, {
16
14
  ms,
17
15
  methodName: String(propertyKey)
18
16
  });
19
- Reflect.defineMetadata(INTERVAL_METADATA, existing, target.constructor);
20
17
  };
21
18
  }
@@ -1,8 +1,4 @@
1
- import type { AsyncModuleOptions, DynamicModule } from '../module/types';
2
- import type { ScheduleModuleOptions } from './schedule.types';
1
+ import type { DynamicModule } from '../module/types';
3
2
  export declare class ScheduleModule {
4
- static forRoot(options?: ScheduleModuleOptions): DynamicModule;
5
- static forRootAsync(options: AsyncModuleOptions<ScheduleModuleOptions> & {
6
- enableTimers?: boolean;
7
- }): DynamicModule;
3
+ static forRoot(): DynamicModule;
8
4
  }
@@ -1,53 +1,15 @@
1
- import { ScheduleExecutor } from "./schedule.executor.js";
2
1
  import { ScheduleRegistry } from "./schedule.registry.js";
3
- import { SCHEDULE_MODULE_OPTIONS } from "./schedule.tokens.js";
4
2
  export class ScheduleModule {
5
- static forRoot(options = {}) {
6
- const { enableTimers = false } = options;
3
+ static forRoot() {
7
4
  const providers = [
8
- {
9
- provide: SCHEDULE_MODULE_OPTIONS,
10
- useValue: options
11
- },
12
5
  ScheduleRegistry
13
6
  ];
14
- const exports = [
15
- SCHEDULE_MODULE_OPTIONS,
16
- ScheduleRegistry
17
- ];
18
- if (enableTimers) {
19
- providers.push(ScheduleExecutor);
20
- exports.push(ScheduleExecutor);
21
- }
22
- return {
23
- module: ScheduleModule,
24
- providers,
25
- exports
26
- };
27
- }
28
- static forRootAsync(options) {
29
- const { enableTimers = false } = options;
30
- const providers = [
31
- {
32
- provide: SCHEDULE_MODULE_OPTIONS,
33
- useFactory: options.useFactory,
34
- inject: options.inject ?? []
35
- },
36
- ScheduleRegistry
37
- ];
38
- const exports = [
39
- SCHEDULE_MODULE_OPTIONS,
40
- ScheduleRegistry
41
- ];
42
- if (enableTimers) {
43
- providers.push(ScheduleExecutor);
44
- exports.push(ScheduleExecutor);
45
- }
46
7
  return {
47
8
  module: ScheduleModule,
48
- imports: options.imports ?? [],
49
9
  providers,
50
- exports
10
+ exports: [
11
+ ScheduleRegistry
12
+ ]
51
13
  };
52
14
  }
53
15
  }
@@ -14,6 +14,7 @@ function _ts_param(paramIndex, decorator) {
14
14
  }
15
15
  import { Injectable, Inject } from "../container/index.js";
16
16
  import { Container } from "../container/container.js";
17
+ import { MetadataRegistry } from "../registry/metadata.registry.js";
17
18
  import { CRON_METADATA, INTERVAL_METADATA } from "./schedule.tokens.js";
18
19
  export class ScheduleRegistry {
19
20
  container;
@@ -26,8 +27,8 @@ export class ScheduleRegistry {
26
27
  const tokens = this.container.getTokens();
27
28
  for (const token of tokens){
28
29
  if (typeof token !== 'function') continue;
29
- const cronMeta = Reflect.getMetadata(CRON_METADATA, token);
30
- const intervalMeta = Reflect.getMetadata(INTERVAL_METADATA, token);
30
+ const cronMeta = MetadataRegistry.getCustomClassMeta(token, CRON_METADATA);
31
+ const intervalMeta = MetadataRegistry.getCustomClassMeta(token, INTERVAL_METADATA);
31
32
  if (!cronMeta && !intervalMeta) continue;
32
33
  let instance;
33
34
  try {
@@ -1,5 +1,2 @@
1
- import { InjectionToken } from '../container/types';
2
- import type { ScheduleModuleOptions } from './schedule.types';
3
- export declare const SCHEDULE_MODULE_OPTIONS: InjectionToken<ScheduleModuleOptions>;
4
1
  export declare const CRON_METADATA = "vela:cron";
5
2
  export declare const INTERVAL_METADATA = "vela:interval";
@@ -1,4 +1,2 @@
1
- import { InjectionToken } from "../container/types.js";
2
- export const SCHEDULE_MODULE_OPTIONS = new InjectionToken('SCHEDULE_MODULE_OPTIONS');
3
1
  export const CRON_METADATA = 'vela:cron';
4
2
  export const INTERVAL_METADATA = 'vela:interval';
@@ -6,6 +6,3 @@ export interface IntervalMetadata {
6
6
  ms: number;
7
7
  methodName: string;
8
8
  }
9
- export interface ScheduleModuleOptions {
10
- enableTimers?: boolean;
11
- }
@@ -0,0 +1,2 @@
1
+ export { ScheduleNodeModule } from './schedule-node.module';
2
+ export { ScheduleExecutor } from './schedule.executor';
@@ -0,0 +1,2 @@
1
+ export { ScheduleNodeModule } from "./schedule-node.module.js";
2
+ export { ScheduleExecutor } from "./schedule.executor.js";
@@ -0,0 +1,4 @@
1
+ import type { DynamicModule } from '../module/types';
2
+ export declare class ScheduleNodeModule {
3
+ static forRoot(): DynamicModule;
4
+ }
@@ -0,0 +1,18 @@
1
+ import { ScheduleRegistry } from "../schedule/schedule.registry.js";
2
+ import { ScheduleExecutor } from "./schedule.executor.js";
3
+ export class ScheduleNodeModule {
4
+ static forRoot() {
5
+ const providers = [
6
+ ScheduleRegistry,
7
+ ScheduleExecutor
8
+ ];
9
+ return {
10
+ module: ScheduleNodeModule,
11
+ providers,
12
+ exports: [
13
+ ScheduleRegistry,
14
+ ScheduleExecutor
15
+ ]
16
+ };
17
+ }
18
+ }
@@ -1,5 +1,5 @@
1
1
  import type { OnApplicationBootstrap, OnModuleDestroy } from '../lifecycle/index';
2
- import { ScheduleRegistry } from './schedule.registry';
2
+ import { ScheduleRegistry } from '../schedule/schedule.registry';
3
3
  export declare class ScheduleExecutor implements OnApplicationBootstrap, OnModuleDestroy {
4
4
  private registry;
5
5
  private intervalTimers;
@@ -12,9 +12,6 @@ export declare class ScheduleExecutor implements OnApplicationBootstrap, OnModul
12
12
  private scheduleInterval;
13
13
  private scheduleCron;
14
14
  private invoke;
15
- private getCronMatcher;
16
- private parseField;
17
- private parseRange;
18
- private parseCronNumber;
15
+ private getMatcher;
19
16
  onModuleDestroy(): void;
20
17
  }
@@ -0,0 +1,91 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ function _ts_metadata(k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ }
10
+ import { Injectable } from "../container/index.js";
11
+ import { parseCron } from "../schedule/cron-matcher.js";
12
+ import { ScheduleRegistry } from "../schedule/schedule.registry.js";
13
+ export class ScheduleExecutor {
14
+ registry;
15
+ intervalTimers = [];
16
+ cronTimers = [];
17
+ cronMatcherCache = new Map();
18
+ lastCronMinute = new Map();
19
+ running = true;
20
+ constructor(registry){
21
+ this.registry = registry;
22
+ }
23
+ onApplicationBootstrap() {
24
+ if (typeof setInterval !== 'function') {
25
+ throw new Error('@velajs/vela/schedule-node requires Node or Bun. Use a platform cron adapter on edge runtimes (e.g. CloudflareApplication.scheduled).');
26
+ }
27
+ for (const job of this.registry.getIntervalJobs()){
28
+ this.scheduleInterval(job.instance, job.methodName, job.ms);
29
+ }
30
+ const cronJobs = this.registry.getCronJobs();
31
+ for(let i = 0; i < cronJobs.length; i++){
32
+ const job = cronJobs[i];
33
+ this.scheduleCron(job.instance, job.methodName, job.expression, i);
34
+ }
35
+ }
36
+ scheduleInterval(instance, methodName, ms) {
37
+ if (!this.running) return;
38
+ const timer = setInterval(()=>{
39
+ void this.invoke(instance, methodName);
40
+ }, ms);
41
+ this.intervalTimers.push(timer);
42
+ }
43
+ scheduleCron(instance, methodName, expression, index) {
44
+ if (!this.running) return;
45
+ const matcher = this.getMatcher(expression);
46
+ if (!matcher) return;
47
+ const jobKey = `${index}:${methodName}:${expression}`;
48
+ const timer = setInterval(()=>{
49
+ const now = new Date();
50
+ const minuteKey = Math.floor(now.getTime() / 60_000);
51
+ if (this.lastCronMinute.get(jobKey) === minuteKey) return;
52
+ if (!matcher(now)) return;
53
+ this.lastCronMinute.set(jobKey, minuteKey);
54
+ void this.invoke(instance, methodName);
55
+ }, 1000);
56
+ this.cronTimers.push(timer);
57
+ }
58
+ async invoke(instance, methodName) {
59
+ try {
60
+ const method = instance[methodName];
61
+ if (typeof method === 'function') {
62
+ await method.call(instance);
63
+ }
64
+ } catch {
65
+ // Swallow errors so the scheduler keeps running
66
+ }
67
+ }
68
+ getMatcher(expression) {
69
+ if (this.cronMatcherCache.has(expression)) {
70
+ return this.cronMatcherCache.get(expression) ?? null;
71
+ }
72
+ const matcher = parseCron(expression);
73
+ this.cronMatcherCache.set(expression, matcher);
74
+ return matcher;
75
+ }
76
+ onModuleDestroy() {
77
+ this.running = false;
78
+ for (const timer of this.intervalTimers)clearInterval(timer);
79
+ for (const timer of this.cronTimers)clearInterval(timer);
80
+ this.intervalTimers = [];
81
+ this.cronTimers = [];
82
+ this.lastCronMinute.clear();
83
+ }
84
+ }
85
+ ScheduleExecutor = _ts_decorate([
86
+ Injectable(),
87
+ _ts_metadata("design:type", Function),
88
+ _ts_metadata("design:paramtypes", [
89
+ typeof ScheduleRegistry === "undefined" ? Object : ScheduleRegistry
90
+ ])
91
+ ], ScheduleExecutor);
@@ -1,11 +1,12 @@
1
- export declare enum LogLevel {
2
- VERBOSE = 0,
3
- DEBUG = 1,
4
- LOG = 2,
5
- WARN = 3,
6
- ERROR = 4,
7
- SILENT = 5
8
- }
1
+ export declare const LogLevel: {
2
+ readonly VERBOSE: 0;
3
+ readonly DEBUG: 1;
4
+ readonly LOG: 2;
5
+ readonly WARN: 3;
6
+ readonly ERROR: 4;
7
+ readonly SILENT: 5;
8
+ };
9
+ export type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];
9
10
  export interface LoggerService {
10
11
  log(message: unknown, ...optionalParams: unknown[]): void;
11
12
  error(message: unknown, ...optionalParams: unknown[]): void;
@@ -8,15 +8,14 @@ function _ts_metadata(k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  }
10
10
  import { Injectable } from "../container/decorators.js";
11
- export var LogLevel = /*#__PURE__*/ function(LogLevel) {
12
- LogLevel[LogLevel["VERBOSE"] = 0] = "VERBOSE";
13
- LogLevel[LogLevel["DEBUG"] = 1] = "DEBUG";
14
- LogLevel[LogLevel["LOG"] = 2] = "LOG";
15
- LogLevel[LogLevel["WARN"] = 3] = "WARN";
16
- LogLevel[LogLevel["ERROR"] = 4] = "ERROR";
17
- LogLevel[LogLevel["SILENT"] = 5] = "SILENT";
18
- return LogLevel;
19
- }({});
11
+ export const LogLevel = {
12
+ VERBOSE: 0,
13
+ DEBUG: 1,
14
+ LOG: 2,
15
+ WARN: 3,
16
+ ERROR: 4,
17
+ SILENT: 5
18
+ };
20
19
  const defaultWriter = (level, line, ...rest)=>{
21
20
  if (level === 'ERROR') return console.error(line, ...rest);
22
21
  if (level === 'WARN') return console.warn(line, ...rest);
@@ -35,7 +34,7 @@ function formatValue(v) {
35
34
  }
36
35
  }
37
36
  export class Logger {
38
- static level = 2;
37
+ static level = LogLevel.LOG;
39
38
  static globalLogger;
40
39
  static globalContextProviders = [];
41
40
  static globalWriter = defaultWriter;
@@ -90,19 +89,19 @@ export class Logger {
90
89
  return child;
91
90
  }
92
91
  log(message, ...optionalParams) {
93
- this.emit('LOG', 2, message, optionalParams);
92
+ this.emit('LOG', LogLevel.LOG, message, optionalParams);
94
93
  }
95
94
  error(message, ...optionalParams) {
96
- this.emit('ERROR', 4, message, optionalParams);
95
+ this.emit('ERROR', LogLevel.ERROR, message, optionalParams);
97
96
  }
98
97
  warn(message, ...optionalParams) {
99
- this.emit('WARN', 3, message, optionalParams);
98
+ this.emit('WARN', LogLevel.WARN, message, optionalParams);
100
99
  }
101
100
  debug(message, ...optionalParams) {
102
- this.emit('DEBUG', 1, message, optionalParams);
101
+ this.emit('DEBUG', LogLevel.DEBUG, message, optionalParams);
103
102
  }
104
103
  verbose(message, ...optionalParams) {
105
- this.emit('VERBOSE', 0, message, optionalParams);
104
+ this.emit('VERBOSE', LogLevel.VERBOSE, message, optionalParams);
106
105
  }
107
106
  emit(levelName, levelValue, message, rest) {
108
107
  if (Logger.level > levelValue) return;
@@ -1,3 +1,3 @@
1
1
  import type { ThrottleConfig } from './throttler.types';
2
- export declare const Throttle: (config: ThrottleConfig) => (target: Function | object, propertyKey?: string | symbol) => void;
3
- export declare const SkipThrottle: () => (target: Function | object, propertyKey?: string | symbol) => void;
2
+ export declare const Throttle: (config: ThrottleConfig) => (target: object, propertyKey?: string | symbol) => void;
3
+ export declare const SkipThrottle: () => (target: object, propertyKey?: string | symbol) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velajs/vela",
3
- "version": "0.10.0",
3
+ "version": "1.1.0",
4
4
  "description": "NestJS-compatible framework for edge runtimes, powered by Hono",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -10,9 +10,17 @@
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.js"
12
12
  },
13
+ "./internal": {
14
+ "types": "./dist/internal.d.ts",
15
+ "import": "./dist/internal.js"
16
+ },
13
17
  "./streaming": {
14
18
  "types": "./dist/streaming/index.d.ts",
15
19
  "import": "./dist/streaming/index.js"
20
+ },
21
+ "./schedule-node": {
22
+ "types": "./dist/schedule-node/index.d.ts",
23
+ "import": "./dist/schedule-node/index.js"
16
24
  }
17
25
  },
18
26
  "files": [
@@ -52,14 +60,6 @@
52
60
  "dependencies": {
53
61
  "hono": "^4"
54
62
  },
55
- "peerDependencies": {
56
- "@velajs/crud": ">=0.1.0"
57
- },
58
- "peerDependenciesMeta": {
59
- "@velajs/crud": {
60
- "optional": true
61
- }
62
- },
63
63
  "devDependencies": {
64
64
  "@swc/cli": "^0.8.0",
65
65
  "@swc/core": "^1.15.11",
@@ -1,169 +0,0 @@
1
- function _ts_decorate(decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- 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;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- }
7
- function _ts_metadata(k, v) {
8
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
- }
10
- import { Injectable } from "../container/index.js";
11
- import { ScheduleRegistry } from "./schedule.registry.js";
12
- export class ScheduleExecutor {
13
- registry;
14
- intervalTimers = [];
15
- cronTimers = [];
16
- cronMatcherCache = new Map();
17
- lastCronMinute = new Map();
18
- running = true;
19
- constructor(registry){
20
- this.registry = registry;
21
- }
22
- onApplicationBootstrap() {
23
- const intervalJobs = this.registry.getIntervalJobs();
24
- const cronJobs = this.registry.getCronJobs();
25
- for (const job of intervalJobs){
26
- this.scheduleInterval(job.instance, job.methodName, job.ms);
27
- }
28
- for(let i = 0; i < cronJobs.length; i++){
29
- const job = cronJobs[i];
30
- this.scheduleCron(job.instance, job.methodName, job.expression, i);
31
- }
32
- }
33
- scheduleInterval(instance, methodName, ms) {
34
- if (!this.running) return;
35
- const timer = setInterval(()=>{
36
- void this.invoke(instance, methodName);
37
- }, ms);
38
- this.intervalTimers.push(timer);
39
- }
40
- scheduleCron(instance, methodName, expression, index) {
41
- if (!this.running) return;
42
- const matcher = this.getCronMatcher(expression);
43
- if (!matcher) {
44
- return;
45
- }
46
- const jobKey = `${index}:${methodName}:${expression}`;
47
- const timer = setInterval(()=>{
48
- const now = new Date();
49
- const minuteKey = Math.floor(now.getTime() / 60_000);
50
- if (this.lastCronMinute.get(jobKey) === minuteKey) {
51
- return;
52
- }
53
- if (!matcher(now)) {
54
- return;
55
- }
56
- this.lastCronMinute.set(jobKey, minuteKey);
57
- void this.invoke(instance, methodName);
58
- }, 1000);
59
- this.cronTimers.push(timer);
60
- }
61
- async invoke(instance, methodName) {
62
- try {
63
- const method = instance[methodName];
64
- if (typeof method === 'function') {
65
- await method.call(instance);
66
- }
67
- } catch {
68
- // Swallow errors to keep the scheduler alive
69
- }
70
- }
71
- getCronMatcher(expression) {
72
- if (this.cronMatcherCache.has(expression)) {
73
- return this.cronMatcherCache.get(expression) ?? null;
74
- }
75
- const fields = expression.trim().split(/\s+/);
76
- if (fields.length !== 5) {
77
- this.cronMatcherCache.set(expression, null);
78
- return null;
79
- }
80
- const [minuteField, hourField, dayField, monthField, weekdayField] = fields;
81
- const minuteMatcher = this.parseField(minuteField, 0, 59);
82
- const hourMatcher = this.parseField(hourField, 0, 23);
83
- const dayMatcher = this.parseField(dayField, 1, 31);
84
- const monthMatcher = this.parseField(monthField, 1, 12);
85
- const weekdayMatcher = this.parseField(weekdayField, 0, 7);
86
- if (!minuteMatcher || !hourMatcher || !dayMatcher || !monthMatcher || !weekdayMatcher) {
87
- this.cronMatcherCache.set(expression, null);
88
- return null;
89
- }
90
- const matcher = (date)=>{
91
- const weekday = date.getDay();
92
- return minuteMatcher(date.getMinutes()) && hourMatcher(date.getHours()) && dayMatcher(date.getDate()) && monthMatcher(date.getMonth() + 1) && weekdayMatcher(weekday);
93
- };
94
- this.cronMatcherCache.set(expression, matcher);
95
- return matcher;
96
- }
97
- parseField(field, min, max) {
98
- const segments = field.split(',');
99
- const predicates = [];
100
- for (const rawSegment of segments){
101
- const segment = rawSegment.trim();
102
- if (!segment) return null;
103
- const stepParts = segment.split('/');
104
- if (stepParts.length > 2) return null;
105
- const baseSegment = stepParts[0];
106
- const step = stepParts.length === 2 ? Number(stepParts[1]) : 1;
107
- if (!Number.isInteger(step) || step <= 0) return null;
108
- const range = this.parseRange(baseSegment, min, max);
109
- if (!range) return null;
110
- predicates.push((value)=>{
111
- if (value < range.start || value > range.end) return false;
112
- return (value - range.start) % step === 0;
113
- });
114
- }
115
- return (value)=>predicates.some((predicate)=>predicate(value));
116
- }
117
- parseRange(segment, min, max) {
118
- if (segment === '*') {
119
- return {
120
- start: min,
121
- end: max
122
- };
123
- }
124
- const bounds = segment.split('-');
125
- if (bounds.length === 1) {
126
- const value = this.parseCronNumber(bounds[0], min, max);
127
- if (value === null) return null;
128
- return {
129
- start: value,
130
- end: value
131
- };
132
- }
133
- if (bounds.length !== 2) return null;
134
- const start = this.parseCronNumber(bounds[0], min, max);
135
- const end = this.parseCronNumber(bounds[1], min, max);
136
- if (start === null || end === null || start > end) return null;
137
- return {
138
- start,
139
- end
140
- };
141
- }
142
- parseCronNumber(raw, min, max) {
143
- const value = Number(raw);
144
- if (!Number.isInteger(value)) return null;
145
- // Cron allows both 0 and 7 for Sunday.
146
- const normalized = max === 7 && value === 7 ? 0 : value;
147
- if (normalized < min || normalized > max) return null;
148
- return normalized;
149
- }
150
- onModuleDestroy() {
151
- this.running = false;
152
- for (const timer of this.intervalTimers){
153
- clearInterval(timer);
154
- }
155
- for (const timer of this.cronTimers){
156
- clearInterval(timer);
157
- }
158
- this.intervalTimers = [];
159
- this.cronTimers = [];
160
- this.lastCronMinute.clear();
161
- }
162
- }
163
- ScheduleExecutor = _ts_decorate([
164
- Injectable(),
165
- _ts_metadata("design:type", Function),
166
- _ts_metadata("design:paramtypes", [
167
- typeof ScheduleRegistry === "undefined" ? Object : ScheduleRegistry
168
- ])
169
- ], ScheduleExecutor);