@dexto/tools-scheduler 1.6.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 (70) hide show
  1. package/LICENSE +44 -0
  2. package/dist/error-codes.cjs +44 -0
  3. package/dist/error-codes.d.cts +21 -0
  4. package/dist/error-codes.d.ts +21 -0
  5. package/dist/error-codes.js +20 -0
  6. package/dist/errors.cjs +163 -0
  7. package/dist/errors.d.cts +64 -0
  8. package/dist/errors.d.ts +64 -0
  9. package/dist/errors.js +138 -0
  10. package/dist/executor.cjs +161 -0
  11. package/dist/executor.d.cts +46 -0
  12. package/dist/executor.d.ts +46 -0
  13. package/dist/executor.js +137 -0
  14. package/dist/index.cjs +89 -0
  15. package/dist/index.d.cts +19 -0
  16. package/dist/index.d.ts +19 -0
  17. package/dist/index.js +56 -0
  18. package/dist/manager.cjs +461 -0
  19. package/dist/manager.d.cts +113 -0
  20. package/dist/manager.d.ts +113 -0
  21. package/dist/manager.js +430 -0
  22. package/dist/schemas.cjs +138 -0
  23. package/dist/schemas.d.cts +263 -0
  24. package/dist/schemas.d.ts +263 -0
  25. package/dist/schemas.js +105 -0
  26. package/dist/storage.cjs +249 -0
  27. package/dist/storage.d.cts +62 -0
  28. package/dist/storage.d.ts +62 -0
  29. package/dist/storage.js +225 -0
  30. package/dist/tool-provider.cjs +239 -0
  31. package/dist/tool-provider.d.cts +34 -0
  32. package/dist/tool-provider.d.ts +34 -0
  33. package/dist/tool-provider.js +212 -0
  34. package/dist/tool-types.cjs +16 -0
  35. package/dist/tool-types.d.cts +9 -0
  36. package/dist/tool-types.d.ts +9 -0
  37. package/dist/tool-types.js +0 -0
  38. package/dist/tools/create-schedule.cjs +75 -0
  39. package/dist/tools/create-schedule.d.cts +14 -0
  40. package/dist/tools/create-schedule.d.ts +14 -0
  41. package/dist/tools/create-schedule.js +51 -0
  42. package/dist/tools/delete-schedule.cjs +45 -0
  43. package/dist/tools/delete-schedule.d.cts +14 -0
  44. package/dist/tools/delete-schedule.d.ts +14 -0
  45. package/dist/tools/delete-schedule.js +21 -0
  46. package/dist/tools/get-history.cjs +63 -0
  47. package/dist/tools/get-history.d.cts +14 -0
  48. package/dist/tools/get-history.d.ts +14 -0
  49. package/dist/tools/get-history.js +39 -0
  50. package/dist/tools/get-schedule.cjs +68 -0
  51. package/dist/tools/get-schedule.d.cts +14 -0
  52. package/dist/tools/get-schedule.d.ts +14 -0
  53. package/dist/tools/get-schedule.js +44 -0
  54. package/dist/tools/list-schedules.cjs +67 -0
  55. package/dist/tools/list-schedules.d.cts +14 -0
  56. package/dist/tools/list-schedules.d.ts +14 -0
  57. package/dist/tools/list-schedules.js +43 -0
  58. package/dist/tools/trigger-schedule.cjs +56 -0
  59. package/dist/tools/trigger-schedule.d.cts +14 -0
  60. package/dist/tools/trigger-schedule.d.ts +14 -0
  61. package/dist/tools/trigger-schedule.js +32 -0
  62. package/dist/tools/update-schedule.cjs +53 -0
  63. package/dist/tools/update-schedule.d.cts +14 -0
  64. package/dist/tools/update-schedule.d.ts +14 -0
  65. package/dist/tools/update-schedule.js +29 -0
  66. package/dist/types.cjs +16 -0
  67. package/dist/types.d.cts +72 -0
  68. package/dist/types.d.ts +72 -0
  69. package/dist/types.js +0 -0
  70. package/package.json +41 -0
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var storage_exports = {};
20
+ __export(storage_exports, {
21
+ ScheduleStorage: () => ScheduleStorage
22
+ });
23
+ module.exports = __toCommonJS(storage_exports);
24
+ var import_errors = require("./errors.js");
25
+ const SCHEDULE_PREFIX = "schedule:";
26
+ const EXECUTION_LOG_PREFIX = "execution:";
27
+ const SCHEDULE_LIST_KEY = "scheduler:schedules";
28
+ class ScheduleStorage {
29
+ constructor(storageManager, maxExecutionHistory, logger) {
30
+ this.storageManager = storageManager;
31
+ this.maxExecutionHistory = maxExecutionHistory;
32
+ this.logger = logger;
33
+ }
34
+ listLock = Promise.resolve();
35
+ /**
36
+ * Save a schedule to persistent storage
37
+ */
38
+ async saveSchedule(schedule) {
39
+ const key = `${SCHEDULE_PREFIX}${schedule.id}`;
40
+ let persisted = false;
41
+ try {
42
+ await this.storageManager.getDatabase().set(key, schedule);
43
+ persisted = true;
44
+ await this.addScheduleToList(schedule.id);
45
+ this.logger.debug(`Schedule ${schedule.id} saved to storage`, { name: schedule.name });
46
+ } catch (error) {
47
+ if (persisted) {
48
+ try {
49
+ await this.storageManager.getDatabase().delete(key);
50
+ } catch (cleanupError) {
51
+ this.logger.error(
52
+ `Failed to rollback schedule ${schedule.id} after list update failure: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`
53
+ );
54
+ }
55
+ }
56
+ throw import_errors.SchedulerError.storageWriteFailed(
57
+ "save schedule",
58
+ error instanceof Error ? error.message : String(error)
59
+ );
60
+ }
61
+ }
62
+ /**
63
+ * Load a schedule from storage
64
+ */
65
+ async loadSchedule(scheduleId) {
66
+ try {
67
+ const key = `${SCHEDULE_PREFIX}${scheduleId}`;
68
+ const schedule = await this.storageManager.getDatabase().get(key);
69
+ return schedule || null;
70
+ } catch (error) {
71
+ throw import_errors.SchedulerError.storageReadFailed(
72
+ "load schedule",
73
+ error instanceof Error ? error.message : String(error)
74
+ );
75
+ }
76
+ }
77
+ /**
78
+ * List all schedules from storage
79
+ */
80
+ async listSchedules() {
81
+ try {
82
+ const scheduleIds = await this.storageManager.getDatabase().get(SCHEDULE_LIST_KEY) || [];
83
+ const schedules = [];
84
+ for (const scheduleId of scheduleIds) {
85
+ const schedule = await this.loadSchedule(scheduleId);
86
+ if (schedule) {
87
+ schedules.push(schedule);
88
+ }
89
+ }
90
+ return schedules;
91
+ } catch (error) {
92
+ throw import_errors.SchedulerError.storageReadFailed(
93
+ "list schedules",
94
+ error instanceof Error ? error.message : String(error)
95
+ );
96
+ }
97
+ }
98
+ /**
99
+ * Delete a schedule from storage
100
+ */
101
+ async deleteSchedule(scheduleId) {
102
+ let removedFromList = false;
103
+ let deletedSchedule = false;
104
+ try {
105
+ const key = `${SCHEDULE_PREFIX}${scheduleId}`;
106
+ await this.removeScheduleFromList(scheduleId);
107
+ removedFromList = true;
108
+ await this.storageManager.getDatabase().delete(key);
109
+ deletedSchedule = true;
110
+ await this.deleteExecutionLogs(scheduleId);
111
+ this.logger.debug(`Schedule ${scheduleId} deleted from storage`);
112
+ } catch (error) {
113
+ if (removedFromList && !deletedSchedule) {
114
+ try {
115
+ await this.addScheduleToList(scheduleId);
116
+ } catch (restoreError) {
117
+ this.logger.error(
118
+ `Failed to restore schedule ${scheduleId} to list after delete failure: ${restoreError instanceof Error ? restoreError.message : String(restoreError)}`
119
+ );
120
+ }
121
+ }
122
+ throw import_errors.SchedulerError.storageWriteFailed(
123
+ "delete schedule",
124
+ error instanceof Error ? error.message : String(error)
125
+ );
126
+ }
127
+ }
128
+ /**
129
+ * Save an execution log
130
+ */
131
+ async saveExecutionLog(log) {
132
+ try {
133
+ const key = `${EXECUTION_LOG_PREFIX}${log.scheduleId}:${log.id}`;
134
+ await this.storageManager.getDatabase().set(key, log);
135
+ await this.pruneExecutionHistory(log.scheduleId);
136
+ this.logger.debug(`Execution log ${log.id} saved for schedule ${log.scheduleId}`, {
137
+ status: log.status
138
+ });
139
+ } catch (error) {
140
+ throw import_errors.SchedulerError.storageWriteFailed(
141
+ "save execution log",
142
+ error instanceof Error ? error.message : String(error)
143
+ );
144
+ }
145
+ }
146
+ /**
147
+ * Get execution logs for a schedule
148
+ */
149
+ async getExecutionLogs(scheduleId, limit) {
150
+ try {
151
+ const prefix = `${EXECUTION_LOG_PREFIX}${scheduleId}:`;
152
+ const keys = await this.storageManager.getDatabase().list(prefix);
153
+ const logs = [];
154
+ for (const key of keys) {
155
+ const log = await this.storageManager.getDatabase().get(key);
156
+ if (log) {
157
+ logs.push(log);
158
+ }
159
+ }
160
+ logs.sort((a, b) => b.triggeredAt - a.triggeredAt);
161
+ return limit ? logs.slice(0, limit) : logs;
162
+ } catch (error) {
163
+ throw import_errors.SchedulerError.storageReadFailed(
164
+ "get execution logs",
165
+ error instanceof Error ? error.message : String(error)
166
+ );
167
+ }
168
+ }
169
+ /**
170
+ * Delete all execution logs for a schedule
171
+ */
172
+ async deleteExecutionLogs(scheduleId) {
173
+ try {
174
+ const prefix = `${EXECUTION_LOG_PREFIX}${scheduleId}:`;
175
+ const keys = await this.storageManager.getDatabase().list(prefix);
176
+ for (const key of keys) {
177
+ await this.storageManager.getDatabase().delete(key);
178
+ }
179
+ this.logger.debug(`Execution logs deleted for schedule ${scheduleId}`);
180
+ } catch (error) {
181
+ this.logger.error(
182
+ `Failed to delete execution logs for schedule ${scheduleId}: ${error instanceof Error ? error.message : String(error)}`
183
+ );
184
+ }
185
+ }
186
+ /**
187
+ * Prune execution history to maintain limit
188
+ */
189
+ async pruneExecutionHistory(scheduleId) {
190
+ try {
191
+ const logs = await this.getExecutionLogs(scheduleId);
192
+ if (logs.length > this.maxExecutionHistory) {
193
+ const logsToDelete = logs.slice(this.maxExecutionHistory);
194
+ for (const log of logsToDelete) {
195
+ const key = `${EXECUTION_LOG_PREFIX}${scheduleId}:${log.id}`;
196
+ await this.storageManager.getDatabase().delete(key);
197
+ }
198
+ this.logger.debug(
199
+ `Pruned ${logsToDelete.length} old execution logs for schedule ${scheduleId}`
200
+ );
201
+ }
202
+ } catch (error) {
203
+ this.logger.error(
204
+ `Failed to prune execution history for schedule ${scheduleId}: ${error instanceof Error ? error.message : String(error)}`
205
+ );
206
+ }
207
+ }
208
+ /**
209
+ * Add schedule ID to master list
210
+ */
211
+ async addScheduleToList(scheduleId) {
212
+ await this.withListLock(async () => {
213
+ const scheduleIds = await this.storageManager.getDatabase().get(SCHEDULE_LIST_KEY) || [];
214
+ if (!scheduleIds.includes(scheduleId)) {
215
+ scheduleIds.push(scheduleId);
216
+ await this.storageManager.getDatabase().set(SCHEDULE_LIST_KEY, scheduleIds);
217
+ }
218
+ });
219
+ }
220
+ /**
221
+ * Remove schedule ID from master list
222
+ */
223
+ async removeScheduleFromList(scheduleId) {
224
+ await this.withListLock(async () => {
225
+ const scheduleIds = await this.storageManager.getDatabase().get(SCHEDULE_LIST_KEY) || [];
226
+ const filtered = scheduleIds.filter((id) => id !== scheduleId);
227
+ await this.storageManager.getDatabase().set(SCHEDULE_LIST_KEY, filtered);
228
+ });
229
+ }
230
+ async withListLock(handler) {
231
+ const previous = this.listLock;
232
+ let release;
233
+ this.listLock = new Promise((resolve) => {
234
+ release = resolve;
235
+ });
236
+ await previous;
237
+ try {
238
+ return await handler();
239
+ } finally {
240
+ if (release) {
241
+ release();
242
+ }
243
+ }
244
+ }
245
+ }
246
+ // Annotate the CommonJS export names for ESM import in node:
247
+ 0 && (module.exports = {
248
+ ScheduleStorage
249
+ });
@@ -0,0 +1,62 @@
1
+ import { StorageManager, Logger } from '@dexto/core';
2
+ import { Schedule, ExecutionLog } from './types.cjs';
3
+ import './schemas.cjs';
4
+ import 'zod';
5
+
6
+ /**
7
+ * Storage layer for schedules and execution logs
8
+ */
9
+
10
+ /**
11
+ * Storage layer for scheduler persistence
12
+ */
13
+ declare class ScheduleStorage {
14
+ private storageManager;
15
+ private maxExecutionHistory;
16
+ private logger;
17
+ private listLock;
18
+ constructor(storageManager: StorageManager, maxExecutionHistory: number, logger: Logger);
19
+ /**
20
+ * Save a schedule to persistent storage
21
+ */
22
+ saveSchedule(schedule: Schedule): Promise<void>;
23
+ /**
24
+ * Load a schedule from storage
25
+ */
26
+ loadSchedule(scheduleId: string): Promise<Schedule | null>;
27
+ /**
28
+ * List all schedules from storage
29
+ */
30
+ listSchedules(): Promise<Schedule[]>;
31
+ /**
32
+ * Delete a schedule from storage
33
+ */
34
+ deleteSchedule(scheduleId: string): Promise<void>;
35
+ /**
36
+ * Save an execution log
37
+ */
38
+ saveExecutionLog(log: ExecutionLog): Promise<void>;
39
+ /**
40
+ * Get execution logs for a schedule
41
+ */
42
+ getExecutionLogs(scheduleId: string, limit?: number): Promise<ExecutionLog[]>;
43
+ /**
44
+ * Delete all execution logs for a schedule
45
+ */
46
+ private deleteExecutionLogs;
47
+ /**
48
+ * Prune execution history to maintain limit
49
+ */
50
+ private pruneExecutionHistory;
51
+ /**
52
+ * Add schedule ID to master list
53
+ */
54
+ private addScheduleToList;
55
+ /**
56
+ * Remove schedule ID from master list
57
+ */
58
+ private removeScheduleFromList;
59
+ private withListLock;
60
+ }
61
+
62
+ export { ScheduleStorage };
@@ -0,0 +1,62 @@
1
+ import { StorageManager, Logger } from '@dexto/core';
2
+ import { Schedule, ExecutionLog } from './types.js';
3
+ import './schemas.js';
4
+ import 'zod';
5
+
6
+ /**
7
+ * Storage layer for schedules and execution logs
8
+ */
9
+
10
+ /**
11
+ * Storage layer for scheduler persistence
12
+ */
13
+ declare class ScheduleStorage {
14
+ private storageManager;
15
+ private maxExecutionHistory;
16
+ private logger;
17
+ private listLock;
18
+ constructor(storageManager: StorageManager, maxExecutionHistory: number, logger: Logger);
19
+ /**
20
+ * Save a schedule to persistent storage
21
+ */
22
+ saveSchedule(schedule: Schedule): Promise<void>;
23
+ /**
24
+ * Load a schedule from storage
25
+ */
26
+ loadSchedule(scheduleId: string): Promise<Schedule | null>;
27
+ /**
28
+ * List all schedules from storage
29
+ */
30
+ listSchedules(): Promise<Schedule[]>;
31
+ /**
32
+ * Delete a schedule from storage
33
+ */
34
+ deleteSchedule(scheduleId: string): Promise<void>;
35
+ /**
36
+ * Save an execution log
37
+ */
38
+ saveExecutionLog(log: ExecutionLog): Promise<void>;
39
+ /**
40
+ * Get execution logs for a schedule
41
+ */
42
+ getExecutionLogs(scheduleId: string, limit?: number): Promise<ExecutionLog[]>;
43
+ /**
44
+ * Delete all execution logs for a schedule
45
+ */
46
+ private deleteExecutionLogs;
47
+ /**
48
+ * Prune execution history to maintain limit
49
+ */
50
+ private pruneExecutionHistory;
51
+ /**
52
+ * Add schedule ID to master list
53
+ */
54
+ private addScheduleToList;
55
+ /**
56
+ * Remove schedule ID from master list
57
+ */
58
+ private removeScheduleFromList;
59
+ private withListLock;
60
+ }
61
+
62
+ export { ScheduleStorage };
@@ -0,0 +1,225 @@
1
+ import { SchedulerError } from "./errors.js";
2
+ const SCHEDULE_PREFIX = "schedule:";
3
+ const EXECUTION_LOG_PREFIX = "execution:";
4
+ const SCHEDULE_LIST_KEY = "scheduler:schedules";
5
+ class ScheduleStorage {
6
+ constructor(storageManager, maxExecutionHistory, logger) {
7
+ this.storageManager = storageManager;
8
+ this.maxExecutionHistory = maxExecutionHistory;
9
+ this.logger = logger;
10
+ }
11
+ listLock = Promise.resolve();
12
+ /**
13
+ * Save a schedule to persistent storage
14
+ */
15
+ async saveSchedule(schedule) {
16
+ const key = `${SCHEDULE_PREFIX}${schedule.id}`;
17
+ let persisted = false;
18
+ try {
19
+ await this.storageManager.getDatabase().set(key, schedule);
20
+ persisted = true;
21
+ await this.addScheduleToList(schedule.id);
22
+ this.logger.debug(`Schedule ${schedule.id} saved to storage`, { name: schedule.name });
23
+ } catch (error) {
24
+ if (persisted) {
25
+ try {
26
+ await this.storageManager.getDatabase().delete(key);
27
+ } catch (cleanupError) {
28
+ this.logger.error(
29
+ `Failed to rollback schedule ${schedule.id} after list update failure: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`
30
+ );
31
+ }
32
+ }
33
+ throw SchedulerError.storageWriteFailed(
34
+ "save schedule",
35
+ error instanceof Error ? error.message : String(error)
36
+ );
37
+ }
38
+ }
39
+ /**
40
+ * Load a schedule from storage
41
+ */
42
+ async loadSchedule(scheduleId) {
43
+ try {
44
+ const key = `${SCHEDULE_PREFIX}${scheduleId}`;
45
+ const schedule = await this.storageManager.getDatabase().get(key);
46
+ return schedule || null;
47
+ } catch (error) {
48
+ throw SchedulerError.storageReadFailed(
49
+ "load schedule",
50
+ error instanceof Error ? error.message : String(error)
51
+ );
52
+ }
53
+ }
54
+ /**
55
+ * List all schedules from storage
56
+ */
57
+ async listSchedules() {
58
+ try {
59
+ const scheduleIds = await this.storageManager.getDatabase().get(SCHEDULE_LIST_KEY) || [];
60
+ const schedules = [];
61
+ for (const scheduleId of scheduleIds) {
62
+ const schedule = await this.loadSchedule(scheduleId);
63
+ if (schedule) {
64
+ schedules.push(schedule);
65
+ }
66
+ }
67
+ return schedules;
68
+ } catch (error) {
69
+ throw SchedulerError.storageReadFailed(
70
+ "list schedules",
71
+ error instanceof Error ? error.message : String(error)
72
+ );
73
+ }
74
+ }
75
+ /**
76
+ * Delete a schedule from storage
77
+ */
78
+ async deleteSchedule(scheduleId) {
79
+ let removedFromList = false;
80
+ let deletedSchedule = false;
81
+ try {
82
+ const key = `${SCHEDULE_PREFIX}${scheduleId}`;
83
+ await this.removeScheduleFromList(scheduleId);
84
+ removedFromList = true;
85
+ await this.storageManager.getDatabase().delete(key);
86
+ deletedSchedule = true;
87
+ await this.deleteExecutionLogs(scheduleId);
88
+ this.logger.debug(`Schedule ${scheduleId} deleted from storage`);
89
+ } catch (error) {
90
+ if (removedFromList && !deletedSchedule) {
91
+ try {
92
+ await this.addScheduleToList(scheduleId);
93
+ } catch (restoreError) {
94
+ this.logger.error(
95
+ `Failed to restore schedule ${scheduleId} to list after delete failure: ${restoreError instanceof Error ? restoreError.message : String(restoreError)}`
96
+ );
97
+ }
98
+ }
99
+ throw SchedulerError.storageWriteFailed(
100
+ "delete schedule",
101
+ error instanceof Error ? error.message : String(error)
102
+ );
103
+ }
104
+ }
105
+ /**
106
+ * Save an execution log
107
+ */
108
+ async saveExecutionLog(log) {
109
+ try {
110
+ const key = `${EXECUTION_LOG_PREFIX}${log.scheduleId}:${log.id}`;
111
+ await this.storageManager.getDatabase().set(key, log);
112
+ await this.pruneExecutionHistory(log.scheduleId);
113
+ this.logger.debug(`Execution log ${log.id} saved for schedule ${log.scheduleId}`, {
114
+ status: log.status
115
+ });
116
+ } catch (error) {
117
+ throw SchedulerError.storageWriteFailed(
118
+ "save execution log",
119
+ error instanceof Error ? error.message : String(error)
120
+ );
121
+ }
122
+ }
123
+ /**
124
+ * Get execution logs for a schedule
125
+ */
126
+ async getExecutionLogs(scheduleId, limit) {
127
+ try {
128
+ const prefix = `${EXECUTION_LOG_PREFIX}${scheduleId}:`;
129
+ const keys = await this.storageManager.getDatabase().list(prefix);
130
+ const logs = [];
131
+ for (const key of keys) {
132
+ const log = await this.storageManager.getDatabase().get(key);
133
+ if (log) {
134
+ logs.push(log);
135
+ }
136
+ }
137
+ logs.sort((a, b) => b.triggeredAt - a.triggeredAt);
138
+ return limit ? logs.slice(0, limit) : logs;
139
+ } catch (error) {
140
+ throw SchedulerError.storageReadFailed(
141
+ "get execution logs",
142
+ error instanceof Error ? error.message : String(error)
143
+ );
144
+ }
145
+ }
146
+ /**
147
+ * Delete all execution logs for a schedule
148
+ */
149
+ async deleteExecutionLogs(scheduleId) {
150
+ try {
151
+ const prefix = `${EXECUTION_LOG_PREFIX}${scheduleId}:`;
152
+ const keys = await this.storageManager.getDatabase().list(prefix);
153
+ for (const key of keys) {
154
+ await this.storageManager.getDatabase().delete(key);
155
+ }
156
+ this.logger.debug(`Execution logs deleted for schedule ${scheduleId}`);
157
+ } catch (error) {
158
+ this.logger.error(
159
+ `Failed to delete execution logs for schedule ${scheduleId}: ${error instanceof Error ? error.message : String(error)}`
160
+ );
161
+ }
162
+ }
163
+ /**
164
+ * Prune execution history to maintain limit
165
+ */
166
+ async pruneExecutionHistory(scheduleId) {
167
+ try {
168
+ const logs = await this.getExecutionLogs(scheduleId);
169
+ if (logs.length > this.maxExecutionHistory) {
170
+ const logsToDelete = logs.slice(this.maxExecutionHistory);
171
+ for (const log of logsToDelete) {
172
+ const key = `${EXECUTION_LOG_PREFIX}${scheduleId}:${log.id}`;
173
+ await this.storageManager.getDatabase().delete(key);
174
+ }
175
+ this.logger.debug(
176
+ `Pruned ${logsToDelete.length} old execution logs for schedule ${scheduleId}`
177
+ );
178
+ }
179
+ } catch (error) {
180
+ this.logger.error(
181
+ `Failed to prune execution history for schedule ${scheduleId}: ${error instanceof Error ? error.message : String(error)}`
182
+ );
183
+ }
184
+ }
185
+ /**
186
+ * Add schedule ID to master list
187
+ */
188
+ async addScheduleToList(scheduleId) {
189
+ await this.withListLock(async () => {
190
+ const scheduleIds = await this.storageManager.getDatabase().get(SCHEDULE_LIST_KEY) || [];
191
+ if (!scheduleIds.includes(scheduleId)) {
192
+ scheduleIds.push(scheduleId);
193
+ await this.storageManager.getDatabase().set(SCHEDULE_LIST_KEY, scheduleIds);
194
+ }
195
+ });
196
+ }
197
+ /**
198
+ * Remove schedule ID from master list
199
+ */
200
+ async removeScheduleFromList(scheduleId) {
201
+ await this.withListLock(async () => {
202
+ const scheduleIds = await this.storageManager.getDatabase().get(SCHEDULE_LIST_KEY) || [];
203
+ const filtered = scheduleIds.filter((id) => id !== scheduleId);
204
+ await this.storageManager.getDatabase().set(SCHEDULE_LIST_KEY, filtered);
205
+ });
206
+ }
207
+ async withListLock(handler) {
208
+ const previous = this.listLock;
209
+ let release;
210
+ this.listLock = new Promise((resolve) => {
211
+ release = resolve;
212
+ });
213
+ await previous;
214
+ try {
215
+ return await handler();
216
+ } finally {
217
+ if (release) {
218
+ release();
219
+ }
220
+ }
221
+ }
222
+ }
223
+ export {
224
+ ScheduleStorage
225
+ };