@push.rocks/taskbuffer 6.0.1 → 6.1.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.
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/taskbuffer',
6
- version: '6.0.1',
6
+ version: '6.1.1',
7
7
  description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDhJQUE4STtDQUM1SixDQUFBIn0=
@@ -8,6 +8,6 @@ export { TaskDebounced } from './taskbuffer.classes.taskdebounced.js';
8
8
  export { TaskConstraintGroup } from './taskbuffer.classes.taskconstraintgroup.js';
9
9
  export { TaskStep } from './taskbuffer.classes.taskstep.js';
10
10
  export type { ITaskStep } from './taskbuffer.classes.taskstep.js';
11
- export type { ITaskMetadata, ITaskExecutionReport, IScheduledTaskInfo, ITaskEvent, TTaskEventType, ITaskConstraintGroupOptions, ITaskExecution } from './taskbuffer.interfaces.js';
11
+ export type { ITaskMetadata, ITaskExecutionReport, IScheduledTaskInfo, ITaskEvent, TTaskEventType, ITaskConstraintGroupOptions, ITaskExecution, IRateLimitConfig, TResultSharingMode } from './taskbuffer.interfaces.js';
12
12
  import * as distributedCoordination from './taskbuffer.classes.distributedcoordinator.js';
13
13
  export { distributedCoordination };
@@ -1,13 +1,17 @@
1
1
  import type { Task } from './taskbuffer.classes.task.js';
2
- import type { ITaskConstraintGroupOptions } from './taskbuffer.interfaces.js';
2
+ import type { ITaskConstraintGroupOptions, IRateLimitConfig, TResultSharingMode } from './taskbuffer.interfaces.js';
3
3
  export declare class TaskConstraintGroup<TData extends Record<string, unknown> = Record<string, unknown>> {
4
4
  name: string;
5
5
  maxConcurrent: number;
6
6
  cooldownMs: number;
7
+ rateLimit: IRateLimitConfig | null;
8
+ resultSharingMode: TResultSharingMode;
7
9
  private constraintKeyForExecution;
8
10
  private shouldExecuteFn?;
9
11
  private runningCounts;
10
12
  private lastCompletionTimes;
13
+ private completionTimestamps;
14
+ private lastResults;
11
15
  constructor(options: ITaskConstraintGroupOptions<TData>);
12
16
  getConstraintKey(task: Task<any, any, TData>, input?: any): string | null;
13
17
  checkShouldExecute(task: Task<any, any, TData>, input?: any): Promise<boolean>;
@@ -16,5 +20,14 @@ export declare class TaskConstraintGroup<TData extends Record<string, unknown> =
16
20
  releaseSlot(subGroupKey: string): void;
17
21
  getCooldownRemaining(subGroupKey: string): number;
18
22
  getRunningCount(subGroupKey: string): number;
23
+ private pruneCompletionTimestamps;
24
+ getRateLimitDelay(subGroupKey: string): number;
25
+ getNextAvailableDelay(subGroupKey: string): number;
26
+ recordResult(subGroupKey: string, result: any): void;
27
+ getLastResult(subGroupKey: string): {
28
+ result: any;
29
+ timestamp: number;
30
+ } | undefined;
31
+ hasResultSharing(): boolean;
19
32
  reset(): void;
20
33
  }
@@ -2,11 +2,15 @@ export class TaskConstraintGroup {
2
2
  constructor(options) {
3
3
  this.runningCounts = new Map();
4
4
  this.lastCompletionTimes = new Map();
5
+ this.completionTimestamps = new Map();
6
+ this.lastResults = new Map();
5
7
  this.name = options.name;
6
8
  this.constraintKeyForExecution = options.constraintKeyForExecution;
7
9
  this.maxConcurrent = options.maxConcurrent ?? Infinity;
8
10
  this.cooldownMs = options.cooldownMs ?? 0;
9
11
  this.shouldExecuteFn = options.shouldExecute;
12
+ this.rateLimit = options.rateLimit ?? null;
13
+ this.resultSharingMode = options.resultSharingMode ?? 'none';
10
14
  }
11
15
  getConstraintKey(task, input) {
12
16
  const key = this.constraintKeyForExecution(task, input);
@@ -32,6 +36,15 @@ export class TaskConstraintGroup {
32
36
  }
33
37
  }
34
38
  }
39
+ if (this.rateLimit) {
40
+ this.pruneCompletionTimestamps(subGroupKey);
41
+ const timestamps = this.completionTimestamps.get(subGroupKey);
42
+ const completedInWindow = timestamps ? timestamps.length : 0;
43
+ const running = this.runningCounts.get(subGroupKey) ?? 0;
44
+ if (completedInWindow + running >= this.rateLimit.maxPerWindow) {
45
+ return false;
46
+ }
47
+ }
35
48
  return true;
36
49
  }
37
50
  acquireSlot(subGroupKey) {
@@ -48,6 +61,11 @@ export class TaskConstraintGroup {
48
61
  this.runningCounts.set(subGroupKey, next);
49
62
  }
50
63
  this.lastCompletionTimes.set(subGroupKey, Date.now());
64
+ if (this.rateLimit) {
65
+ const timestamps = this.completionTimestamps.get(subGroupKey) ?? [];
66
+ timestamps.push(Date.now());
67
+ this.completionTimestamps.set(subGroupKey, timestamps);
68
+ }
51
69
  }
52
70
  getCooldownRemaining(subGroupKey) {
53
71
  if (this.cooldownMs <= 0) {
@@ -63,9 +81,59 @@ export class TaskConstraintGroup {
63
81
  getRunningCount(subGroupKey) {
64
82
  return this.runningCounts.get(subGroupKey) ?? 0;
65
83
  }
84
+ // Rate limit helpers
85
+ pruneCompletionTimestamps(subGroupKey) {
86
+ const timestamps = this.completionTimestamps.get(subGroupKey);
87
+ if (!timestamps || !this.rateLimit)
88
+ return;
89
+ const cutoff = Date.now() - this.rateLimit.windowMs;
90
+ let i = 0;
91
+ while (i < timestamps.length && timestamps[i] <= cutoff) {
92
+ i++;
93
+ }
94
+ if (i > 0) {
95
+ timestamps.splice(0, i);
96
+ }
97
+ }
98
+ getRateLimitDelay(subGroupKey) {
99
+ if (!this.rateLimit)
100
+ return 0;
101
+ this.pruneCompletionTimestamps(subGroupKey);
102
+ const timestamps = this.completionTimestamps.get(subGroupKey);
103
+ const completedInWindow = timestamps ? timestamps.length : 0;
104
+ const running = this.runningCounts.get(subGroupKey) ?? 0;
105
+ if (completedInWindow + running < this.rateLimit.maxPerWindow) {
106
+ return 0;
107
+ }
108
+ // If only running tasks fill the window (no completions yet), we can't compute a delay
109
+ if (!timestamps || timestamps.length === 0) {
110
+ return 1; // minimal delay; drain will re-check after running tasks complete
111
+ }
112
+ // The oldest timestamp in the window determines when a slot opens
113
+ const oldestInWindow = timestamps[0];
114
+ const expiry = oldestInWindow + this.rateLimit.windowMs;
115
+ return Math.max(0, expiry - Date.now());
116
+ }
117
+ getNextAvailableDelay(subGroupKey) {
118
+ return Math.max(this.getCooldownRemaining(subGroupKey), this.getRateLimitDelay(subGroupKey));
119
+ }
120
+ // Result sharing helpers
121
+ recordResult(subGroupKey, result) {
122
+ if (this.resultSharingMode === 'none')
123
+ return;
124
+ this.lastResults.set(subGroupKey, { result, timestamp: Date.now() });
125
+ }
126
+ getLastResult(subGroupKey) {
127
+ return this.lastResults.get(subGroupKey);
128
+ }
129
+ hasResultSharing() {
130
+ return this.resultSharingMode !== 'none';
131
+ }
66
132
  reset() {
67
133
  this.runningCounts.clear();
68
134
  this.lastCompletionTimes.clear();
135
+ this.completionTimestamps.clear();
136
+ this.lastResults.clear();
69
137
  }
70
138
  }
71
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFza2J1ZmZlci5jbGFzc2VzLnRhc2tjb25zdHJhaW50Z3JvdXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy90YXNrYnVmZmVyLmNsYXNzZXMudGFza2NvbnN0cmFpbnRncm91cC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxNQUFNLE9BQU8sbUJBQW1CO0lBVTlCLFlBQVksT0FBMkM7UUFIL0Msa0JBQWEsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUMxQyx3QkFBbUIsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUd0RCxJQUFJLENBQUMsSUFBSSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUM7UUFDekIsSUFBSSxDQUFDLHlCQUF5QixHQUFHLE9BQU8sQ0FBQyx5QkFBeUIsQ0FBQztRQUNuRSxJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQyxhQUFhLElBQUksUUFBUSxDQUFDO1FBQ3ZELElBQUksQ0FBQyxVQUFVLEdBQUcsT0FBTyxDQUFDLFVBQVUsSUFBSSxDQUFDLENBQUM7UUFDMUMsSUFBSSxDQUFDLGVBQWUsR0FBRyxPQUFPLENBQUMsYUFBYSxDQUFDO0lBQy9DLENBQUM7SUFFTSxnQkFBZ0IsQ0FBQyxJQUEyQixFQUFFLEtBQVc7UUFDOUQsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLHlCQUF5QixDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN4RCxPQUFPLEdBQUcsSUFBSSxJQUFJLENBQUM7SUFDckIsQ0FBQztJQUVNLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxJQUEyQixFQUFFLEtBQVc7UUFDdEUsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUMxQixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFTSxNQUFNLENBQUMsV0FBbUI7UUFDL0IsTUFB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
139
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFza2J1ZmZlci5jbGFzc2VzLnRhc2tjb25zdHJhaW50Z3JvdXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy90YXNrYnVmZmVyLmNsYXNzZXMudGFza2NvbnN0cmFpbnRncm91cC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxNQUFNLE9BQU8sbUJBQW1CO0lBYzlCLFlBQVksT0FBMkM7UUFML0Msa0JBQWEsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUMxQyx3QkFBbUIsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUNoRCx5QkFBb0IsR0FBRyxJQUFJLEdBQUcsRUFBb0IsQ0FBQztRQUNuRCxnQkFBVyxHQUFHLElBQUksR0FBRyxFQUE4QyxDQUFDO1FBRzFFLElBQUksQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztRQUN6QixJQUFJLENBQUMseUJBQXlCLEdBQUcsT0FBTyxDQUFDLHlCQUF5QixDQUFDO1FBQ25FLElBQUksQ0FBQyxhQUFhLEdBQUcsT0FBTyxDQUFDLGFBQWEsSUFBSSxRQUFRLENBQUM7UUFDdkQsSUFBSSxDQUFDLFVBQVUsR0FBRyxPQUFPLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQztRQUMxQyxJQUFJLENBQUMsZUFBZSxHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUM7UUFDN0MsSUFBSSxDQUFDLFNBQVMsR0FBRyxPQUFPLENBQUMsU0FBUyxJQUFJLElBQUksQ0FBQztRQUMzQyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsT0FBTyxDQUFDLGlCQUFpQixJQUFJLE1BQU0sQ0FBQztJQUMvRCxDQUFDO0lBRU0sZ0JBQWdCLENBQUMsSUFBMkIsRUFBRSxLQUFXO1FBQzlELE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDeEQsT0FBTyxHQUFHLElBQUksSUFBSSxDQUFDO0lBQ3JCLENBQUM7SUFFTSxLQUFLLENBQUMsa0JB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
@@ -108,7 +108,14 @@ export class TaskManager {
108
108
  return undefined;
109
109
  }
110
110
  try {
111
- return await task.trigger(input);
111
+ const result = await task.trigger(input);
112
+ // Record result for groups with result sharing (only on true success, not caught errors)
113
+ if (!task.lastError) {
114
+ for (const { group, key } of groups) {
115
+ group.recordResult(key, result);
116
+ }
117
+ }
118
+ return result;
112
119
  }
113
120
  finally {
114
121
  // Release slots
@@ -140,6 +147,15 @@ export class TaskManager {
140
147
  });
141
148
  continue;
142
149
  }
150
+ // Check result sharing — if any applicable group has a shared result, resolve immediately
151
+ const sharingGroups = applicableGroups.filter(({ group }) => group.hasResultSharing());
152
+ if (sharingGroups.length > 0) {
153
+ const groupWithResult = sharingGroups.find(({ group, key }) => group.getLastResult(key) !== undefined);
154
+ if (groupWithResult) {
155
+ entry.deferred.resolve(groupWithResult.group.getLastResult(groupWithResult.key).result);
156
+ continue;
157
+ }
158
+ }
143
159
  const allCanRun = applicableGroups.every(({ group, key }) => group.canRun(key));
144
160
  if (allCanRun) {
145
161
  // executeWithConstraintTracking handles shouldExecute check internally
@@ -147,9 +163,9 @@ export class TaskManager {
147
163
  }
148
164
  else {
149
165
  stillQueued.push(entry);
150
- // Track shortest cooldown for timer scheduling
166
+ // Track shortest delay for timer scheduling (cooldown + rate limit)
151
167
  for (const { group, key } of applicableGroups) {
152
- const remaining = group.getCooldownRemaining(key);
168
+ const remaining = group.getNextAvailableDelay(key);
153
169
  if (remaining > 0 && remaining < shortestCooldown) {
154
170
  shortestCooldown = remaining;
155
171
  }
@@ -368,4 +384,4 @@ export class TaskManager {
368
384
  }
369
385
  }
370
386
  }
371
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFza2J1ZmZlci5jbGFzc2VzLnRhc2ttYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvdGFza2J1ZmZlci5jbGFzc2VzLnRhc2ttYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0seUJBQXlCLENBQUM7QUFDbkQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDZDQUE2QyxDQUFDO0FBQ2xGLE9BQU8sRUFDTCw4QkFBOEIsR0FFL0IsTUFBTSxnREFBZ0QsQ0FBQztBQUV4RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFZakQsTUFBTSxPQUFPLFdBQVc7SUFldEIsWUFBWSxVQUEwQyxFQUFFO1FBZGpELGFBQVEsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3pDLFlBQU8sR0FBRyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUF1QixDQUFDO1FBQ2xELGdCQUFXLEdBQUcsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQWMsQ0FBQztRQUNyRSxzQkFBaUIsR0FBRyxJQUFJLEdBQUcsRUFBMEQsQ0FBQztRQUN0RixtQkFBYyxHQUFHLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN0RCxZQUFPLEdBQW1DO1lBQy9DLHNCQUFzQixFQUFFLElBQUk7U0FDN0IsQ0FBQztRQUVGLG9CQUFvQjtRQUNiLHFCQUFnQixHQUErQixFQUFFLENBQUM7UUFDakQsb0JBQWUsR0FBNEIsRUFBRSxDQUFDO1FBQzlDLGVBQVUsR0FBeUMsSUFBSSxDQUFDO1FBRzlELElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxD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
387
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFza2J1ZmZlci5jbGFzc2VzLnRhc2ttYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvdGFza2J1ZmZlci5jbGFzc2VzLnRhc2ttYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0seUJBQXlCLENBQUM7QUFDbkQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDZDQUE2QyxDQUFDO0FBQ2xGLE9BQU8sRUFDTCw4QkFBOEIsR0FFL0IsTUFBTSxnREFBZ0QsQ0FBQztBQUV4RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFZakQsTUFBTSxPQUFPLFdBQVc7SUFldEIsWUFBWSxVQUEwQyxFQUFFO1FBZGpELGFBQVEsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3pDLFlBQU8sR0FBRyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUF1QixDQUFDO1FBQ2xELGdCQUFXLEdBQUcsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQWMsQ0FBQztRQUNyRSxzQkFBaUIsR0FBRyxJQUFJLEdBQUcsRUFBMEQsQ0FBQztRQUN0RixtQkFBYyxHQUFHLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN0RCxZQUFPLEdBQW1DO1lBQy9DLHNCQUFzQixFQUFFLElBQUk7U0FDN0IsQ0FBQztRQUVGLG9CQUFvQjtRQUNiLHFCQUFnQixHQUErQixFQUFFLENBQUM7UUFDakQsb0JBQWUsR0FBNEIsRUFBRSxDQUFDO1FBQzlDLGVBQVUsR0FBeUMsSUFBSSxDQUFDO1FBRzlELElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxD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
@@ -1,11 +1,18 @@
1
1
  import type { ITaskStep } from './taskbuffer.classes.taskstep.js';
2
2
  import type { Task } from './taskbuffer.classes.task.js';
3
+ export interface IRateLimitConfig {
4
+ maxPerWindow: number;
5
+ windowMs: number;
6
+ }
7
+ export type TResultSharingMode = 'none' | 'share-latest';
3
8
  export interface ITaskConstraintGroupOptions<TData extends Record<string, unknown> = Record<string, unknown>> {
4
9
  name: string;
5
10
  constraintKeyForExecution: (task: Task<any, any, TData>, input?: any) => string | null | undefined;
6
11
  maxConcurrent?: number;
7
12
  cooldownMs?: number;
8
13
  shouldExecute?: (task: Task<any, any, TData>, input?: any) => boolean | Promise<boolean>;
14
+ rateLimit?: IRateLimitConfig;
15
+ resultSharingMode?: TResultSharingMode;
9
16
  }
10
17
  export interface ITaskExecution<TData extends Record<string, unknown> = Record<string, unknown>> {
11
18
  task: Task<any, any, TData>;
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/taskbuffer',
6
- version: '6.0.1',
6
+ version: '6.1.1',
7
7
  description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHNfd2ViLzAwX2NvbW1pdGluZm9fZGF0YS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRztJQUN4QixJQUFJLEVBQUUsd0JBQXdCO0lBQzlCLE9BQU8sRUFBRSxPQUFPO0lBQ2hCLFdBQVcsRUFBRSw4SUFBOEk7Q0FDNUosQ0FBQSJ9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/taskbuffer",
3
- "version": "6.0.1",
3
+ "version": "6.1.1",
4
4
  "private": false,
5
5
  "description": "A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.",
6
6
  "main": "dist_ts/index.js",
package/readme.hints.md CHANGED
@@ -12,14 +12,31 @@
12
12
  - Typed data bag accessible as `task.data`
13
13
 
14
14
  ### TaskConstraintGroup
15
- - `new TaskConstraintGroup<TData>({ name, constraintKeyForExecution, maxConcurrent?, cooldownMs?, shouldExecute? })`
15
+ - `new TaskConstraintGroup<TData>({ name, constraintKeyForExecution, maxConcurrent?, cooldownMs?, shouldExecute?, rateLimit?, resultSharingMode? })`
16
16
  - `constraintKeyForExecution(task, input?)` returns a string key (constraint applies) or `null` (skip). Receives both task and runtime input.
17
17
  - `shouldExecute(task, input?)` — optional pre-execution check. Returns `false` to skip (deferred resolves `undefined`). Can be async.
18
18
  - `maxConcurrent` (default: `Infinity`) — max concurrent tasks per key
19
19
  - `cooldownMs` (default: `0`) — minimum ms gap between completions per key
20
- - Methods: `getConstraintKey(task, input?)`, `checkShouldExecute(task, input?)`, `canRun(key)`, `acquireSlot(key)`, `releaseSlot(key)`, `getCooldownRemaining(key)`, `getRunningCount(key)`, `reset()`
20
+ - `rateLimit` (optional) `{ maxPerWindow: number, windowMs: number }` sliding window rate limiter. Counts both running + completed tasks in window.
21
+ - `resultSharingMode` (default: `'none'`) — `'none'` | `'share-latest'`. When `'share-latest'`, queued tasks for the same key resolve with the first task's result without executing.
22
+ - Methods: `getConstraintKey(task, input?)`, `checkShouldExecute(task, input?)`, `canRun(key)`, `acquireSlot(key)`, `releaseSlot(key)`, `getCooldownRemaining(key)`, `getRateLimitDelay(key)`, `getNextAvailableDelay(key)`, `getRunningCount(key)`, `recordResult(key, result)`, `getLastResult(key)`, `hasResultSharing()`, `reset()`
21
23
  - `ITaskExecution<TData>` type exported from index — `{ task, input }` tuple
22
24
 
25
+ ### Rate Limiting (v6.1.0+)
26
+ - Sliding window rate limiter: `rateLimit: { maxPerWindow: N, windowMs: ms }`
27
+ - Counts running + completed tasks against the window cap
28
+ - Per-key independence: saturating key A doesn't block key B
29
+ - Composable with `maxConcurrent` and `cooldownMs`
30
+ - `getNextAvailableDelay(key)` returns `Math.max(cooldownRemaining, rateLimitDelay)` — unified "how long until I can run" answer
31
+ - Drain timer auto-schedules based on shortest delay across all constraints
32
+
33
+ ### Result Sharing (v6.1.0+)
34
+ - `resultSharingMode: 'share-latest'` — queued tasks for the same key get the first task's result without executing
35
+ - Only successful results are shared (errors from `catchErrors: true` or thrown errors are NOT shared)
36
+ - `shouldExecute` is NOT called for shared results (the task's purpose was already fulfilled)
37
+ - `lastResults` persists until `reset()` — for time-bounded sharing, use `shouldExecute` to control staleness
38
+ - Composable with rate limiting: rate-limited waiters get shared result without waiting for the window
39
+
23
40
  ### TaskManager Constraint Integration
24
41
  - `manager.addConstraintGroup(group)` / `manager.removeConstraintGroup(name)`
25
42
  - `triggerTaskByName()`, `triggerTask()`, `addExecuteRemoveTask()`, cron callbacks all route through `triggerTaskConstrained()`
@@ -28,7 +45,7 @@
28
45
 
29
46
  ### Exported from index.ts
30
47
  - `TaskConstraintGroup` class
31
- - `ITaskConstraintGroupOptions` type
48
+ - `ITaskConstraintGroupOptions`, `IRateLimitConfig`, `TResultSharingMode` types
32
49
 
33
50
  ## Error Handling (v3.6.0+)
34
51
  - `Task` now has `catchErrors` constructor option (default: `false`)
package/readme.md CHANGED
@@ -13,7 +13,7 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
13
13
  ## 🌟 Features
14
14
 
15
15
  - **🎯 Type-Safe Task Management** — Full TypeScript support with generics and type inference
16
- - **🔒 Constraint-Based Concurrency** — Per-key mutual exclusion, group concurrency limits, and cooldown enforcement via `TaskConstraintGroup`
16
+ - **🔒 Constraint-Based Concurrency** — Per-key mutual exclusion, group concurrency limits, cooldown enforcement, sliding-window rate limiting, and result sharing via `TaskConstraintGroup`
17
17
  - **📊 Real-Time Progress Tracking** — Step-based progress with percentage weights
18
18
  - **⚡ Smart Buffering** — Intelligent request debouncing and batching
19
19
  - **⏰ Cron Scheduling** — Schedule tasks with cron expressions
@@ -311,6 +311,105 @@ const [cert1, cert2, cert3] = await Promise.all([r1, r2, r3]);
311
311
  - Has closure access to external state modified by prior executions
312
312
  - If multiple constraint groups have `shouldExecute`, **all** must return `true`
313
313
 
314
+ ### Sliding Window Rate Limiting
315
+
316
+ Enforce "N completions per time window" with burst capability. Unlike `cooldownMs` (which forces even spacing between executions), `rateLimit` allows bursts up to the cap, then blocks until the window slides:
317
+
318
+ ```typescript
319
+ // Let's Encrypt style: 300 new orders per 3 hours
320
+ const acmeRateLimit = new TaskConstraintGroup({
321
+ name: 'acme-rate',
322
+ constraintKeyForExecution: () => 'acme-account',
323
+ rateLimit: {
324
+ maxPerWindow: 300,
325
+ windowMs: 3 * 60 * 60 * 1000, // 3 hours
326
+ },
327
+ });
328
+
329
+ manager.addConstraintGroup(acmeRateLimit);
330
+
331
+ // All 300 can burst immediately. The 301st waits until the oldest
332
+ // completion falls out of the 3-hour window.
333
+ for (const domain of domains) {
334
+ manager.triggerTaskConstrained(certTask, { domain });
335
+ }
336
+ ```
337
+
338
+ Compose multiple rate limits for layered protection:
339
+
340
+ ```typescript
341
+ // Per-domain weekly cap AND global order rate
342
+ const perDomainWeekly = new TaskConstraintGroup({
343
+ name: 'per-domain-weekly',
344
+ constraintKeyForExecution: (task, input) => input.registeredDomain,
345
+ rateLimit: { maxPerWindow: 50, windowMs: 7 * 24 * 60 * 60 * 1000 },
346
+ });
347
+
348
+ const globalOrderRate = new TaskConstraintGroup({
349
+ name: 'global-order-rate',
350
+ constraintKeyForExecution: () => 'global',
351
+ rateLimit: { maxPerWindow: 300, windowMs: 3 * 60 * 60 * 1000 },
352
+ });
353
+
354
+ manager.addConstraintGroup(perDomainWeekly);
355
+ manager.addConstraintGroup(globalOrderRate);
356
+ ```
357
+
358
+ Combine with `maxConcurrent` and `cooldownMs` for fine-grained control:
359
+
360
+ ```typescript
361
+ const throttled = new TaskConstraintGroup({
362
+ name: 'acme-throttle',
363
+ constraintKeyForExecution: () => 'acme',
364
+ maxConcurrent: 5, // max 5 concurrent requests
365
+ cooldownMs: 1000, // 1s gap after each completion
366
+ rateLimit: {
367
+ maxPerWindow: 300,
368
+ windowMs: 3 * 60 * 60 * 1000,
369
+ },
370
+ });
371
+ ```
372
+
373
+ ### Result Sharing — Deduplication for Concurrent Requests
374
+
375
+ When multiple callers request the same resource concurrently, `resultSharingMode: 'share-latest'` ensures only one execution occurs. All queued waiters receive the same result:
376
+
377
+ ```typescript
378
+ const certMutex = new TaskConstraintGroup({
379
+ name: 'cert-per-tld',
380
+ constraintKeyForExecution: (task, input) => extractTld(input.domain),
381
+ maxConcurrent: 1,
382
+ resultSharingMode: 'share-latest',
383
+ });
384
+
385
+ manager.addConstraintGroup(certMutex);
386
+
387
+ const certTask = new Task({
388
+ name: 'obtain-cert',
389
+ taskFunction: async (input) => {
390
+ return await acmeClient.obtainWildcard(input.domain);
391
+ },
392
+ });
393
+ manager.addTask(certTask);
394
+
395
+ // Three requests for *.example.com arrive simultaneously
396
+ const [cert1, cert2, cert3] = await Promise.all([
397
+ manager.triggerTaskConstrained(certTask, { domain: 'api.example.com' }),
398
+ manager.triggerTaskConstrained(certTask, { domain: 'www.example.com' }),
399
+ manager.triggerTaskConstrained(certTask, { domain: 'mail.example.com' }),
400
+ ]);
401
+
402
+ // Only ONE ACME request was made.
403
+ // cert1 === cert2 === cert3 — all callers got the same cert object.
404
+ ```
405
+
406
+ **Result sharing semantics:**
407
+
408
+ - `shouldExecute` is NOT called for shared results (the task's purpose was already fulfilled)
409
+ - Error results are NOT shared — queued tasks execute independently after a failure
410
+ - `lastResults` persists until `reset()` — for time-bounded sharing, use `shouldExecute` to control staleness
411
+ - Composable with rate limiting: rate-limited waiters get shared results without waiting for the window
412
+
314
413
  ### How It Works
315
414
 
316
415
  When you trigger a task through `TaskManager` (via `triggerTask`, `triggerTaskByName`, `addExecuteRemoveTask`, or cron), the manager:
@@ -319,8 +418,9 @@ When you trigger a task through `TaskManager` (via `triggerTask`, `triggerTaskBy
319
418
  2. If no constraints apply (all matchers return `null`) → checks `shouldExecute` → runs or skips
320
419
  3. If all applicable constraints have capacity → acquires slots → checks `shouldExecute` → runs or skips
321
420
  4. If any constraint blocks → enqueues the task; when a running task completes, the queue is drained
322
- 5. Cooldown-blocked tasks auto-retry after the shortest remaining cooldown expires
323
- 6. Queued tasks re-check `shouldExecute` when their turn comes stale work is automatically pruned
421
+ 5. Cooldown/rate-limit-blocked tasks auto-retry after the shortest remaining delay expires
422
+ 6. Queued tasks check for shared results first (if any group has `resultSharingMode: 'share-latest'`)
423
+ 7. Queued tasks re-check `shouldExecute` when their turn comes — stale work is automatically pruned
324
424
 
325
425
  ## 🎯 Core Concepts
326
426
 
@@ -926,6 +1026,8 @@ const acmeTasks = manager.getTasksMetadataByLabel('tenantId', 'acme');
926
1026
  | `maxConcurrent` | `number` | `Infinity` | Max concurrent tasks per key |
927
1027
  | `cooldownMs` | `number` | `0` | Minimum ms between completions per key |
928
1028
  | `shouldExecute` | `(task, input?) => boolean \| Promise<boolean>` | — | Pre-execution check. Return `false` to skip; deferred resolves `undefined`. |
1029
+ | `rateLimit` | `IRateLimitConfig` | — | Sliding window: `{ maxPerWindow, windowMs }`. Counts running + completed tasks. |
1030
+ | `resultSharingMode` | `TResultSharingMode` | `'none'` | `'none'` or `'share-latest'`. Queued tasks get first task's result without executing. |
929
1031
 
930
1032
  ### TaskConstraintGroup Methods
931
1033
 
@@ -933,12 +1035,17 @@ const acmeTasks = manager.getTasksMetadataByLabel('tenantId', 'acme');
933
1035
  | --- | --- | --- |
934
1036
  | `getConstraintKey(task, input?)` | `string \| null` | Get the constraint key for a task + input |
935
1037
  | `checkShouldExecute(task, input?)` | `Promise<boolean>` | Run the `shouldExecute` callback (defaults to `true`) |
936
- | `canRun(key)` | `boolean` | Check if a slot is available |
1038
+ | `canRun(key)` | `boolean` | Check if a slot is available (considers concurrency, cooldown, and rate limit) |
937
1039
  | `acquireSlot(key)` | `void` | Claim a running slot |
938
- | `releaseSlot(key)` | `void` | Release a slot and record completion time |
1040
+ | `releaseSlot(key)` | `void` | Release a slot and record completion time + rate-limit timestamp |
939
1041
  | `getCooldownRemaining(key)` | `number` | Milliseconds until cooldown expires |
1042
+ | `getRateLimitDelay(key)` | `number` | Milliseconds until a rate-limit slot opens |
1043
+ | `getNextAvailableDelay(key)` | `number` | Max of cooldown + rate-limit delay — unified "when can I run" |
940
1044
  | `getRunningCount(key)` | `number` | Current running count for key |
941
- | `reset()` | `void` | Clear all state |
1045
+ | `recordResult(key, result)` | `void` | Store result for sharing (no-op if mode is `'none'`) |
1046
+ | `getLastResult(key)` | `{result, timestamp} \| undefined` | Get last shared result for key |
1047
+ | `hasResultSharing()` | `boolean` | Whether result sharing is enabled |
1048
+ | `reset()` | `void` | Clear all state (running counts, cooldowns, rate-limit timestamps, shared results) |
942
1049
 
943
1050
  ### TaskManager Methods
944
1051
 
@@ -986,6 +1093,8 @@ import type {
986
1093
  ITaskStep,
987
1094
  ITaskFunction,
988
1095
  ITaskConstraintGroupOptions,
1096
+ IRateLimitConfig,
1097
+ TResultSharingMode,
989
1098
  StepNames,
990
1099
  } from '@push.rocks/taskbuffer';
991
1100
  ```
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/taskbuffer',
6
- version: '6.0.1',
6
+ version: '6.1.1',
7
7
  description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
8
8
  }
package/ts/index.ts CHANGED
@@ -12,7 +12,7 @@ export { TaskStep } from './taskbuffer.classes.taskstep.js';
12
12
  export type { ITaskStep } from './taskbuffer.classes.taskstep.js';
13
13
 
14
14
  // Metadata interfaces
15
- export type { ITaskMetadata, ITaskExecutionReport, IScheduledTaskInfo, ITaskEvent, TTaskEventType, ITaskConstraintGroupOptions, ITaskExecution } from './taskbuffer.interfaces.js';
15
+ export type { ITaskMetadata, ITaskExecutionReport, IScheduledTaskInfo, ITaskEvent, TTaskEventType, ITaskConstraintGroupOptions, ITaskExecution, IRateLimitConfig, TResultSharingMode } from './taskbuffer.interfaces.js';
16
16
 
17
17
  import * as distributedCoordination from './taskbuffer.classes.distributedcoordinator.js';
18
18
  export { distributedCoordination };
@@ -1,15 +1,19 @@
1
1
  import type { Task } from './taskbuffer.classes.task.js';
2
- import type { ITaskConstraintGroupOptions } from './taskbuffer.interfaces.js';
2
+ import type { ITaskConstraintGroupOptions, IRateLimitConfig, TResultSharingMode } from './taskbuffer.interfaces.js';
3
3
 
4
4
  export class TaskConstraintGroup<TData extends Record<string, unknown> = Record<string, unknown>> {
5
5
  public name: string;
6
6
  public maxConcurrent: number;
7
7
  public cooldownMs: number;
8
+ public rateLimit: IRateLimitConfig | null;
9
+ public resultSharingMode: TResultSharingMode;
8
10
  private constraintKeyForExecution: (task: Task<any, any, TData>, input?: any) => string | null | undefined;
9
11
  private shouldExecuteFn?: (task: Task<any, any, TData>, input?: any) => boolean | Promise<boolean>;
10
12
 
11
13
  private runningCounts = new Map<string, number>();
12
14
  private lastCompletionTimes = new Map<string, number>();
15
+ private completionTimestamps = new Map<string, number[]>();
16
+ private lastResults = new Map<string, { result: any; timestamp: number }>();
13
17
 
14
18
  constructor(options: ITaskConstraintGroupOptions<TData>) {
15
19
  this.name = options.name;
@@ -17,6 +21,8 @@ export class TaskConstraintGroup<TData extends Record<string, unknown> = Record<
17
21
  this.maxConcurrent = options.maxConcurrent ?? Infinity;
18
22
  this.cooldownMs = options.cooldownMs ?? 0;
19
23
  this.shouldExecuteFn = options.shouldExecute;
24
+ this.rateLimit = options.rateLimit ?? null;
25
+ this.resultSharingMode = options.resultSharingMode ?? 'none';
20
26
  }
21
27
 
22
28
  public getConstraintKey(task: Task<any, any, TData>, input?: any): string | null {
@@ -47,6 +53,16 @@ export class TaskConstraintGroup<TData extends Record<string, unknown> = Record<
47
53
  }
48
54
  }
49
55
 
56
+ if (this.rateLimit) {
57
+ this.pruneCompletionTimestamps(subGroupKey);
58
+ const timestamps = this.completionTimestamps.get(subGroupKey);
59
+ const completedInWindow = timestamps ? timestamps.length : 0;
60
+ const running = this.runningCounts.get(subGroupKey) ?? 0;
61
+ if (completedInWindow + running >= this.rateLimit.maxPerWindow) {
62
+ return false;
63
+ }
64
+ }
65
+
50
66
  return true;
51
67
  }
52
68
 
@@ -64,6 +80,12 @@ export class TaskConstraintGroup<TData extends Record<string, unknown> = Record<
64
80
  this.runningCounts.set(subGroupKey, next);
65
81
  }
66
82
  this.lastCompletionTimes.set(subGroupKey, Date.now());
83
+
84
+ if (this.rateLimit) {
85
+ const timestamps = this.completionTimestamps.get(subGroupKey) ?? [];
86
+ timestamps.push(Date.now());
87
+ this.completionTimestamps.set(subGroupKey, timestamps);
88
+ }
67
89
  }
68
90
 
69
91
  public getCooldownRemaining(subGroupKey: string): number {
@@ -82,8 +104,61 @@ export class TaskConstraintGroup<TData extends Record<string, unknown> = Record<
82
104
  return this.runningCounts.get(subGroupKey) ?? 0;
83
105
  }
84
106
 
107
+ // Rate limit helpers
108
+ private pruneCompletionTimestamps(subGroupKey: string): void {
109
+ const timestamps = this.completionTimestamps.get(subGroupKey);
110
+ if (!timestamps || !this.rateLimit) return;
111
+ const cutoff = Date.now() - this.rateLimit.windowMs;
112
+ let i = 0;
113
+ while (i < timestamps.length && timestamps[i] <= cutoff) {
114
+ i++;
115
+ }
116
+ if (i > 0) {
117
+ timestamps.splice(0, i);
118
+ }
119
+ }
120
+
121
+ public getRateLimitDelay(subGroupKey: string): number {
122
+ if (!this.rateLimit) return 0;
123
+ this.pruneCompletionTimestamps(subGroupKey);
124
+ const timestamps = this.completionTimestamps.get(subGroupKey);
125
+ const completedInWindow = timestamps ? timestamps.length : 0;
126
+ const running = this.runningCounts.get(subGroupKey) ?? 0;
127
+ if (completedInWindow + running < this.rateLimit.maxPerWindow) {
128
+ return 0;
129
+ }
130
+ // If only running tasks fill the window (no completions yet), we can't compute a delay
131
+ if (!timestamps || timestamps.length === 0) {
132
+ return 1; // minimal delay; drain will re-check after running tasks complete
133
+ }
134
+ // The oldest timestamp in the window determines when a slot opens
135
+ const oldestInWindow = timestamps[0];
136
+ const expiry = oldestInWindow + this.rateLimit.windowMs;
137
+ return Math.max(0, expiry - Date.now());
138
+ }
139
+
140
+ public getNextAvailableDelay(subGroupKey: string): number {
141
+ return Math.max(this.getCooldownRemaining(subGroupKey), this.getRateLimitDelay(subGroupKey));
142
+ }
143
+
144
+ // Result sharing helpers
145
+ public recordResult(subGroupKey: string, result: any): void {
146
+ if (this.resultSharingMode === 'none') return;
147
+ this.lastResults.set(subGroupKey, { result, timestamp: Date.now() });
148
+ }
149
+
150
+ public getLastResult(subGroupKey: string): { result: any; timestamp: number } | undefined {
151
+ return this.lastResults.get(subGroupKey);
152
+ }
153
+
154
+ public hasResultSharing(): boolean {
155
+ return this.resultSharingMode !== 'none';
156
+ }
157
+
85
158
  public reset(): void {
86
159
  this.runningCounts.clear();
87
160
  this.lastCompletionTimes.clear();
161
+ this.completionTimestamps.clear();
162
+ this.lastResults.clear();
88
163
  }
89
164
  }
@@ -143,7 +143,14 @@ export class TaskManager {
143
143
  }
144
144
 
145
145
  try {
146
- return await task.trigger(input);
146
+ const result = await task.trigger(input);
147
+ // Record result for groups with result sharing (only on true success, not caught errors)
148
+ if (!task.lastError) {
149
+ for (const { group, key } of groups) {
150
+ group.recordResult(key, result);
151
+ }
152
+ }
153
+ return result;
147
154
  } finally {
148
155
  // Release slots
149
156
  for (const { group, key } of groups) {
@@ -181,6 +188,18 @@ export class TaskManager {
181
188
  continue;
182
189
  }
183
190
 
191
+ // Check result sharing — if any applicable group has a shared result, resolve immediately
192
+ const sharingGroups = applicableGroups.filter(({ group }) => group.hasResultSharing());
193
+ if (sharingGroups.length > 0) {
194
+ const groupWithResult = sharingGroups.find(({ group, key }) =>
195
+ group.getLastResult(key) !== undefined
196
+ );
197
+ if (groupWithResult) {
198
+ entry.deferred.resolve(groupWithResult.group.getLastResult(groupWithResult.key)!.result);
199
+ continue;
200
+ }
201
+ }
202
+
184
203
  const allCanRun = applicableGroups.every(({ group, key }) => group.canRun(key));
185
204
  if (allCanRun) {
186
205
  // executeWithConstraintTracking handles shouldExecute check internally
@@ -190,9 +209,9 @@ export class TaskManager {
190
209
  );
191
210
  } else {
192
211
  stillQueued.push(entry);
193
- // Track shortest cooldown for timer scheduling
212
+ // Track shortest delay for timer scheduling (cooldown + rate limit)
194
213
  for (const { group, key } of applicableGroups) {
195
- const remaining = group.getCooldownRemaining(key);
214
+ const remaining = group.getNextAvailableDelay(key);
196
215
  if (remaining > 0 && remaining < shortestCooldown) {
197
216
  shortestCooldown = remaining;
198
217
  }
@@ -1,12 +1,21 @@
1
1
  import type { ITaskStep } from './taskbuffer.classes.taskstep.js';
2
2
  import type { Task } from './taskbuffer.classes.task.js';
3
3
 
4
+ export interface IRateLimitConfig {
5
+ maxPerWindow: number; // max completions allowed within the sliding window
6
+ windowMs: number; // sliding window duration in ms
7
+ }
8
+
9
+ export type TResultSharingMode = 'none' | 'share-latest';
10
+
4
11
  export interface ITaskConstraintGroupOptions<TData extends Record<string, unknown> = Record<string, unknown>> {
5
12
  name: string;
6
13
  constraintKeyForExecution: (task: Task<any, any, TData>, input?: any) => string | null | undefined;
7
14
  maxConcurrent?: number; // default: Infinity
8
15
  cooldownMs?: number; // default: 0
9
16
  shouldExecute?: (task: Task<any, any, TData>, input?: any) => boolean | Promise<boolean>;
17
+ rateLimit?: IRateLimitConfig;
18
+ resultSharingMode?: TResultSharingMode; // default: 'none'
10
19
  }
11
20
 
12
21
  export interface ITaskExecution<TData extends Record<string, unknown> = Record<string, unknown>> {
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/taskbuffer',
6
- version: '6.0.1',
6
+ version: '6.1.1',
7
7
  description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
8
8
  }