eternal-timer 2.1.0 → 2.2.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.
Files changed (50) hide show
  1. package/README.md +58 -25
  2. package/dist/cjs/JSONLTimersManager.cjs +198 -0
  3. package/dist/cjs/JSONLTimersManager.d.ts +63 -0
  4. package/dist/cjs/JSONLTimersManager.d.ts.map +1 -0
  5. package/dist/cjs/JSONLTimersManager.js.map +1 -0
  6. package/dist/cjs/Log.cjs +82 -0
  7. package/dist/cjs/Log.d.ts +8 -0
  8. package/dist/cjs/Log.d.ts.map +1 -0
  9. package/dist/cjs/Log.js.map +1 -0
  10. package/dist/cjs/PlainTextTimersManager.cjs +200 -0
  11. package/dist/cjs/PlainTextTimersManager.d.ts +60 -0
  12. package/dist/cjs/PlainTextTimersManager.d.ts.map +1 -0
  13. package/dist/cjs/PlainTextTimersManager.js.map +1 -0
  14. package/dist/cjs/TimersManager.cjs +39 -0
  15. package/dist/cjs/TimersManager.d.ts +75 -0
  16. package/dist/cjs/TimersManager.d.ts.map +1 -0
  17. package/dist/cjs/TimersManager.js.map +1 -0
  18. package/dist/cjs/index.cjs +5 -279
  19. package/dist/cjs/index.d.ts +3 -72
  20. package/dist/cjs/index.d.ts.map +1 -1
  21. package/dist/cjs/index.js.map +1 -1
  22. package/dist/cjs/types.cjs +3 -0
  23. package/dist/cjs/types.d.ts +8 -0
  24. package/dist/cjs/types.d.ts.map +1 -0
  25. package/dist/cjs/types.js.map +1 -0
  26. package/dist/esm/JSONLTimersManager.d.ts +63 -0
  27. package/dist/esm/JSONLTimersManager.d.ts.map +1 -0
  28. package/dist/esm/JSONLTimersManager.js +191 -0
  29. package/dist/esm/JSONLTimersManager.js.map +1 -0
  30. package/dist/esm/Log.d.ts +8 -0
  31. package/dist/esm/Log.d.ts.map +1 -0
  32. package/dist/esm/Log.js +45 -0
  33. package/dist/esm/Log.js.map +1 -0
  34. package/dist/esm/PlainTextTimersManager.d.ts +60 -0
  35. package/dist/esm/PlainTextTimersManager.d.ts.map +1 -0
  36. package/dist/esm/PlainTextTimersManager.js +193 -0
  37. package/dist/esm/PlainTextTimersManager.js.map +1 -0
  38. package/dist/esm/TimersManager.d.ts +75 -0
  39. package/dist/esm/TimersManager.d.ts.map +1 -0
  40. package/dist/esm/TimersManager.js +32 -0
  41. package/dist/esm/TimersManager.js.map +1 -0
  42. package/dist/esm/index.d.ts +3 -72
  43. package/dist/esm/index.d.ts.map +1 -1
  44. package/dist/esm/index.js +2 -274
  45. package/dist/esm/index.js.map +1 -1
  46. package/dist/esm/types.d.ts +8 -0
  47. package/dist/esm/types.d.ts.map +1 -0
  48. package/dist/esm/types.js +2 -0
  49. package/dist/esm/types.js.map +1 -0
  50. package/package.json +12 -4
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PlainTextTimersManager = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const uuid_1 = require("uuid");
9
+ const readline_1 = __importDefault(require("readline"));
10
+ const TimersManager_js_1 = require("./TimersManager.cjs");
11
+ const Log_js_1 = require("./Log.cjs");
12
+ class PlainTextTimersManager extends TimersManager_js_1.TimersManager {
13
+ getDefaultFilename() {
14
+ return ".timers";
15
+ }
16
+ /**
17
+ * checkTimerfileSyntax
18
+ * @description Checks the syntax of the timer file.
19
+ * @param fileData
20
+ * @returns void
21
+ * @throws If syntax is invalid
22
+ */
23
+ async checkTimerfileSyntax(fileData) {
24
+ const throwing = () => {
25
+ throw new Error(`Timer file's syntax is wrong`);
26
+ };
27
+ const timersData = fileData
28
+ .split('\n')
29
+ .map(l => l.trim())
30
+ .filter(l => l !== "");
31
+ for (const timerData of timersData) {
32
+ const timerArray = timerData.split(/\s+/);
33
+ if (timerArray.length !== 3)
34
+ throwing();
35
+ if (timerArray[0]?.length !== 36)
36
+ throwing();
37
+ if (timerArray[1].trim() === "")
38
+ throwing();
39
+ if (timerArray[2].trim() === "")
40
+ throwing();
41
+ }
42
+ return;
43
+ }
44
+ /**
45
+ * createTimer
46
+ * @description Creates a new timer.
47
+ * @param length
48
+ * @returns Promise that resolves to the timer ID (UUID)
49
+ * @throws If length is invalid(e.g. length < 0) or file operation fails
50
+ * @example
51
+ * const manager = new PlainTextTimersManager();
52
+ * const newTimer = await manager.createTimer(5000);
53
+ * // newTimer will be id of the timer
54
+ */
55
+ async createTimer(length) {
56
+ try {
57
+ if (length < 0) {
58
+ throw new Error(`Invailed length: ${length}`);
59
+ }
60
+ const timersRaw = await fs_1.default.promises.readFile(this.timerfiledir, "utf-8");
61
+ await this.checkTimerfileSyntax(timersRaw);
62
+ length = Math.trunc(length);
63
+ // uuid, start, end
64
+ const id = (0, uuid_1.v4)();
65
+ const now = Date.now();
66
+ const newTimerData = `${id} ${now.toString()} ${(now + length).toString()}`;
67
+ await fs_1.default.promises.appendFile(this.timerfiledir, newTimerData + "\n");
68
+ return id;
69
+ }
70
+ catch (e) {
71
+ throw new Error(`Error when creating timer: ${e}`);
72
+ }
73
+ }
74
+ /**
75
+ * removeTimer
76
+ * @description Removes a timer by ID.
77
+ * @param id ID of the timer to remove
78
+ * @returns void
79
+ * @throws If file operation fails
80
+ * @example
81
+ * await manager.removeTimer(id);
82
+ */
83
+ async removeTimer(id) {
84
+ try {
85
+ const timersRaw = await fs_1.default.promises.readFile(this.timerfiledir, "utf-8");
86
+ await this.checkTimerfileSyntax(timersRaw);
87
+ const rl = readline_1.default.createInterface({
88
+ input: fs_1.default.createReadStream(this.timerfiledir),
89
+ crlfDelay: Infinity,
90
+ });
91
+ const newTimersDataLines = [];
92
+ let found = false;
93
+ for await (const line of rl) {
94
+ if (!line.trim())
95
+ continue;
96
+ const [timerId] = line.split(" ");
97
+ if (timerId === id) {
98
+ found = true;
99
+ continue;
100
+ }
101
+ newTimersDataLines.push(line);
102
+ }
103
+ if (!found) {
104
+ throw new Error(`Timer with id ${id} not found`);
105
+ }
106
+ await fs_1.default.promises.writeFile(this.timerfiledir, newTimersDataLines.join("\n"), "utf-8");
107
+ return;
108
+ }
109
+ catch (e) {
110
+ throw new Error(`Error when removing timer: ${e}`);
111
+ }
112
+ }
113
+ /**
114
+ * checkTimers
115
+ * @description Starts monitoring expired timers asynchronously and returns immediately. The callback is invoked asynchronously when a timer expires.
116
+ * The callback is awaited before continuing.
117
+ * @param callback Function invoked when an expired timer is detected (called asynchronously)
118
+ * @param interval (number, optional): Check interval in milliseconds (default: 200ms)
119
+ * @throws If file operation fails
120
+ * @returns (NodeJS.Timeout) intervalId interval id of checkTimers
121
+ * @example
122
+ * const interval = manager.checkTimers((timer) => {
123
+ * console.log(`A timer was stopped: ${timer.id}`);
124
+ * });
125
+ */
126
+ checkTimers(callback, interval = 200) {
127
+ return setInterval(async () => {
128
+ if (this.checkLock)
129
+ return;
130
+ this.checkLock = true;
131
+ try {
132
+ const rl = readline_1.default.createInterface({
133
+ input: fs_1.default.createReadStream(this.timerfiledir),
134
+ crlfDelay: Infinity,
135
+ });
136
+ for await (const line of rl) {
137
+ if (!line.trim())
138
+ continue;
139
+ const [id, startStr, stopStr] = line.split(" ");
140
+ const timer = {
141
+ id: id,
142
+ start: Number(startStr),
143
+ stop: Number(stopStr),
144
+ };
145
+ const now = Date.now();
146
+ if (Number(timer.stop) <= now) {
147
+ await this.removeTimer(timer.id);
148
+ callback(timer).catch(async (e) => {
149
+ await Log_js_1.Log.ensureLogger();
150
+ if (Log_js_1.Log.loggerInstance) {
151
+ Log_js_1.Log.loggerInstance.error(`Error in timer callback: ${e}`);
152
+ }
153
+ });
154
+ }
155
+ }
156
+ }
157
+ catch (e) {
158
+ await Log_js_1.Log.ensureLogger();
159
+ if (Log_js_1.Log.loggerInstance) {
160
+ Log_js_1.Log.loggerInstance.error(`Error when checking alarm: ${e}`);
161
+ }
162
+ }
163
+ finally {
164
+ this.checkLock = false;
165
+ }
166
+ }, interval);
167
+ }
168
+ /**
169
+ * showTimers
170
+ * @description Retrieves all active timers.
171
+ * @returns Array of `Timer` objects
172
+ * @throws If file operation fails
173
+ * @example
174
+ * const timers = await manager.showTimers();
175
+ * console.log(JSON.stringify(timers))
176
+ */
177
+ async showTimers() {
178
+ try {
179
+ const timersRaw = await fs_1.default.promises.readFile(this.timerfiledir, "utf-8");
180
+ const timersData = timersRaw.split(/\r?\n/);
181
+ const timersJSON = [];
182
+ for (const timerData of timersData) {
183
+ const splitedTimerData = timerData.split(" ");
184
+ if (!timerData.trim())
185
+ continue;
186
+ timersJSON.push({
187
+ id: splitedTimerData[0],
188
+ start: Number(splitedTimerData[1]),
189
+ stop: Number(splitedTimerData[2]),
190
+ });
191
+ }
192
+ return timersJSON;
193
+ }
194
+ catch (e) {
195
+ throw new Error(`Error when showing timers: ${e}`);
196
+ }
197
+ }
198
+ }
199
+ exports.PlainTextTimersManager = PlainTextTimersManager;
200
+ //# sourceMappingURL=PlainTextTimersManager.js.map
@@ -0,0 +1,60 @@
1
+ import type { Timer } from "./types.cjs";
2
+ import { TimersManager } from "./TimersManager.cjs";
3
+ export declare class PlainTextTimersManager extends TimersManager {
4
+ protected getDefaultFilename(): string;
5
+ /**
6
+ * checkTimerfileSyntax
7
+ * @description Checks the syntax of the timer file.
8
+ * @param fileData
9
+ * @returns void
10
+ * @throws If syntax is invalid
11
+ */
12
+ protected checkTimerfileSyntax(fileData: string): Promise<void>;
13
+ /**
14
+ * createTimer
15
+ * @description Creates a new timer.
16
+ * @param length
17
+ * @returns Promise that resolves to the timer ID (UUID)
18
+ * @throws If length is invalid(e.g. length < 0) or file operation fails
19
+ * @example
20
+ * const manager = new PlainTextTimersManager();
21
+ * const newTimer = await manager.createTimer(5000);
22
+ * // newTimer will be id of the timer
23
+ */
24
+ createTimer(length: number): Promise<string>;
25
+ /**
26
+ * removeTimer
27
+ * @description Removes a timer by ID.
28
+ * @param id ID of the timer to remove
29
+ * @returns void
30
+ * @throws If file operation fails
31
+ * @example
32
+ * await manager.removeTimer(id);
33
+ */
34
+ removeTimer(id: string): Promise<void>;
35
+ /**
36
+ * checkTimers
37
+ * @description Starts monitoring expired timers asynchronously and returns immediately. The callback is invoked asynchronously when a timer expires.
38
+ * The callback is awaited before continuing.
39
+ * @param callback Function invoked when an expired timer is detected (called asynchronously)
40
+ * @param interval (number, optional): Check interval in milliseconds (default: 200ms)
41
+ * @throws If file operation fails
42
+ * @returns (NodeJS.Timeout) intervalId interval id of checkTimers
43
+ * @example
44
+ * const interval = manager.checkTimers((timer) => {
45
+ * console.log(`A timer was stopped: ${timer.id}`);
46
+ * });
47
+ */
48
+ checkTimers(callback: (timer: Timer) => Promise<void>, interval?: number): NodeJS.Timeout;
49
+ /**
50
+ * showTimers
51
+ * @description Retrieves all active timers.
52
+ * @returns Array of `Timer` objects
53
+ * @throws If file operation fails
54
+ * @example
55
+ * const timers = await manager.showTimers();
56
+ * console.log(JSON.stringify(timers))
57
+ */
58
+ showTimers(): Promise<Timer[]>;
59
+ }
60
+ //# sourceMappingURL=PlainTextTimersManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlainTextTimersManager.d.ts","sourceRoot":"","sources":["../../src/PlainTextTimersManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,qBAAa,sBAAuB,SAAQ,aAAa;IACxD,SAAS,CAAC,kBAAkB,IAAI,MAAM;IAItC;;;;;;OAMG;cACa,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBrE;;;;;;;;;;OAUG;IACU,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAsBzD;;;;;;;;OAQG;IACU,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8BnD;;;;;;;;;;;;OAYG;IACI,WAAW,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAE,MAAY,GAAG,MAAM,CAAC,OAAO;IAyCrG;;;;;;;;OAQG;IACU,UAAU,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;CAoB3C"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlainTextTimersManager.js","sourceRoot":"","sources":["../../src/PlainTextTimersManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TimersManager = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const searchRoot_js_1 = __importDefault(require("./searchRoot.cjs"));
10
+ /**
11
+ * TimersManager
12
+ * @description
13
+ * Manages timers stored in a file.
14
+ * (This is a abstract class)
15
+ *
16
+ * - Timers are persisted in a file
17
+ * - Expired timers are detected by polling
18
+ */
19
+ class TimersManager {
20
+ timerfiledir;
21
+ checkLock = false;
22
+ /**
23
+ * constructor
24
+ * @param timerfiledir(string, optional)
25
+ * If omitted, `.timers.jsonl` under the project root is used.
26
+ */
27
+ constructor(timerfiledir) {
28
+ this.timerfiledir =
29
+ timerfiledir ?? path_1.default.join((0, searchRoot_js_1.default)(), this.getDefaultFilename());
30
+ try {
31
+ fs_1.default.accessSync(this.timerfiledir);
32
+ }
33
+ catch {
34
+ fs_1.default.writeFileSync(this.timerfiledir, "");
35
+ }
36
+ }
37
+ }
38
+ exports.TimersManager = TimersManager;
39
+ //# sourceMappingURL=TimersManager.js.map
@@ -0,0 +1,75 @@
1
+ import type { Timer } from "./types.cjs";
2
+ /**
3
+ * TimersManager
4
+ * @description
5
+ * Manages timers stored in a file.
6
+ * (This is a abstract class)
7
+ *
8
+ * - Timers are persisted in a file
9
+ * - Expired timers are detected by polling
10
+ */
11
+ export declare abstract class TimersManager {
12
+ protected readonly timerfiledir: string;
13
+ protected checkLock: boolean;
14
+ protected abstract getDefaultFilename(): string;
15
+ /**
16
+ * constructor
17
+ * @param timerfiledir(string, optional)
18
+ * If omitted, `.timers.jsonl` under the project root is used.
19
+ */
20
+ constructor(timerfiledir?: string);
21
+ /**
22
+ * checkTimerfileSyntax
23
+ * @description Checks the syntax of the timer file.
24
+ * @param fileData
25
+ * @returns void
26
+ * @throws If syntax is invalid
27
+ */
28
+ protected abstract checkTimerfileSyntax(fileData: string): Promise<void>;
29
+ /**
30
+ * createTimer
31
+ * @description Creates a new timer.
32
+ * @param length Timer duration in milliseconds
33
+ * @returns Promise that resolves to the timer ID (UUID)
34
+ * @throws If length is invalid(e.g. length < 0) or file operation fails
35
+ * @example
36
+ * const manager = new TimersManager();
37
+ * const newTimer = await manager.createTimer(5000);
38
+ * // newTimer will be id of the timer
39
+ */
40
+ abstract createTimer(length: number, title?: string, description?: string): Promise<string>;
41
+ /**
42
+ * removeTimer
43
+ * @description Removes a timer by ID.
44
+ * @param id ID of the timer to remove
45
+ * @returns void
46
+ * @throws If file operation fails
47
+ * @example
48
+ * await manager.removeTimer(id);
49
+ */
50
+ abstract removeTimer(id: string): Promise<void>;
51
+ /**
52
+ * @description Starts monitoring expired timers asynchronously and returns immediately. The callback is invoked asynchronously when a timer expires.
53
+ * The callback is awaited before continuing.
54
+ * @param callback Function invoked when an expired timer is detected (called asynchronously)
55
+ * @param interval (number, optional): Check interval in milliseconds (default: 200ms)
56
+ * @throws If file operation fails
57
+ * @returns (NodeJS.Timeout) intervalId interval id of checkTimers
58
+ * @example
59
+ * const interval = manager.checkTimers((timer) => {
60
+ * console.log(`A timer was stopped: ${timer.id}`);
61
+ * });
62
+ */
63
+ abstract checkTimers(callback: (timer: Timer) => Promise<void>, interval?: number): NodeJS.Timeout;
64
+ /**
65
+ * showTimers
66
+ * @description Retrieves all active timers.
67
+ * @returns Array of `Timer` objects
68
+ * @throws If file operation fails
69
+ * @example
70
+ * const timers = await manager.showTimers();
71
+ * console.log(JSON.stringify(timers))
72
+ */
73
+ abstract showTimers(): Promise<Timer[]>;
74
+ }
75
+ //# sourceMappingURL=TimersManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimersManager.d.ts","sourceRoot":"","sources":["../../src/TimersManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;;GAQG;AACH,8BAAsB,aAAa;IAClC,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IACxC,SAAS,CAAC,SAAS,EAAE,OAAO,CAAS;IAErC,SAAS,CAAC,QAAQ,CAAC,kBAAkB,IAAI,MAAM;IAE/C;;;;OAIM;gBAEL,YAAY,CAAC,EAAE,MAAM;IAYtB;;;;;;OAMG;IACH,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAExE;;;;;;;;;;OAUM;aACU,WAAW,CAAC,MAAM,EAAC,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAEjG;;;;;;;;OAQM;aACU,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAEtD;;;;;;;;;;;OAWM;aACU,WAAW,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO;IAEzG;;;;;;;;OAQM;aACU,UAAU,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;CAC9C"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimersManager.js","sourceRoot":"","sources":["../../src/TimersManager.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AACxB,4CAAoB;AACpB,oEAAyC;AAGzC;;;;;;;;GAQG;AACH,MAAsB,aAAa;IACf,YAAY,CAAS;IAC9B,SAAS,GAAY,KAAK,CAAC;IAIrC;;;;OAIM;IACN,YACC,YAAqB;QAErB,IAAI,CAAC,YAAY;YACP,YAAY,IAAI,cAAI,CAAC,IAAI,CAAC,IAAA,uBAAU,GAAE,EAAE,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAC;QAE7E,IAAI,CAAC;YACJ,YAAE,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACR,YAAE,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QACzC,CAAC;IACF,CAAC;CA2DD;AAjFD,sCAiFC"}
@@ -1,282 +1,8 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.TimersManager = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- const searchRoot_js_1 = __importDefault(require("./searchRoot.cjs"));
10
- const uuid_1 = require("uuid");
11
- async function checkTimerfileSyntax(fileData, isJSONLines) {
12
- const throwing = () => {
13
- throw new Error(`Timer file's syntax is wrong`);
14
- };
15
- const timersData = fileData
16
- .split('\n')
17
- .map(l => l.trim())
18
- .filter(l => l !== "");
19
- if (isJSONLines) {
20
- for (const timerData of timersData) {
21
- const parsed = JSON.parse(timerData);
22
- if (!parsed.id || typeof parsed.id !== "string" || parsed.id.length !== 36)
23
- throwing();
24
- if (!parsed.start || typeof parsed.start !== "number" || parsed.start.toString().trim() === "")
25
- throwing();
26
- if (!parsed.stop || typeof parsed.stop !== "number" || parsed.stop.toString().trim() === "")
27
- throwing();
28
- if (parsed.title && typeof parsed.title !== "string")
29
- throwing();
30
- if (parsed.description && typeof parsed.description !== "string")
31
- throwing();
32
- }
33
- }
34
- else {
35
- for (const timerData of timersData) {
36
- const timerArray = timerData.split(/\s+/);
37
- if (timerArray.length !== 3)
38
- throwing();
39
- if (timerArray[0]?.length !== 36)
40
- throwing();
41
- if (timerArray[1].trim() === "")
42
- throwing();
43
- if (timerArray[2].trim() === "")
44
- throwing();
45
- }
46
- }
47
- return;
48
- }
49
- /**
50
- * TimersManager
51
- * @description
52
- * Manages timers stored in a file.
53
- * Each timer is stored as: `id start stop`.
54
- *
55
- * - Timers are persisted in a file
56
- * - Expired timers are detected by polling
57
- */
58
- class TimersManager {
59
- timerfiledir;
60
- isJSONLines;
61
- checkLock = false;
62
- /**
63
- * constructor
64
- * @param timerfiledir(string, optional)
65
- * If omitted, `.timers.jsonl` under the project root is used.
66
- */
67
- constructor(timerfiledir) {
68
- this.timerfiledir =
69
- timerfiledir ?? path_1.default.join((0, searchRoot_js_1.default)(), ".timers.jsonl");
70
- this.isJSONLines = this.timerfiledir.endsWith(".jsonl");
71
- try {
72
- fs_1.default.accessSync(this.timerfiledir);
73
- }
74
- catch {
75
- fs_1.default.writeFileSync(this.timerfiledir, "");
76
- }
77
- }
78
- /**
79
- * createTimer
80
- * @description Creates a new timer.
81
- * @param length Timer duration in milliseconds
82
- * @returns Promise that resolves to the timer ID (UUID)
83
- * @throws If length is invalid(e.g. length < 0) or file operation fails
84
- * @example
85
- * const manager = new TimersManager();
86
- * const newTimer = await manager.createTimer(5000);
87
- * // newTimer will be id of the timer
88
- */
89
- async createTimer(length, title, description) {
90
- try {
91
- if (length < 0) {
92
- throw new Error(`Invailed length: ${length}`);
93
- }
94
- if (!this.isJSONLines) {
95
- if (title || description) {
96
- // out warn
97
- }
98
- }
99
- const timersRaw = await fs_1.default.promises.readFile(this.timerfiledir, "utf-8");
100
- await checkTimerfileSyntax(timersRaw, this.isJSONLines);
101
- length = Math.trunc(length);
102
- // uuid, start, end
103
- const id = (0, uuid_1.v4)();
104
- const now = Date.now();
105
- let newTimerData;
106
- if (this.isJSONLines) {
107
- const json = {
108
- id,
109
- start: now,
110
- stop: (now + length),
111
- ...(title !== undefined && { title }),
112
- ...(description !== undefined && { description }),
113
- };
114
- newTimerData = JSON.stringify(json, null, 0);
115
- }
116
- else {
117
- newTimerData = `${id} ${now.toString()} ${(now + length).toString()}`;
118
- }
119
- await fs_1.default.promises.appendFile(this.timerfiledir, newTimerData + "\n");
120
- return id;
121
- }
122
- catch (e) {
123
- throw new Error(`Error when creating timer: ${e}`);
124
- }
125
- }
126
- /**
127
- * removeTimer
128
- * @description Removes a timer by ID.
129
- * @param id ID of the timer to remove
130
- * @returns void
131
- * @throws If file operation fails
132
- * @example
133
- * await manager.removeTimer(id);
134
- */
135
- async removeTimer(id) {
136
- try {
137
- const timersRaw = await fs_1.default.promises.readFile(this.timerfiledir, "utf-8");
138
- await checkTimerfileSyntax(timersRaw, this.isJSONLines);
139
- let newTimersData = "";
140
- if (this.isJSONLines) {
141
- const timersData = timersRaw
142
- .split(/\r?\n/)
143
- .filter(t => t.trim())
144
- .map(line => JSON.parse(line));
145
- let found = false;
146
- for (const timerData of timersData) {
147
- if (!timerData)
148
- continue;
149
- if (timerData.id === id) {
150
- found = true;
151
- continue;
152
- }
153
- newTimersData += `${JSON.stringify(timerData, null, 0)}\n`;
154
- }
155
- if (!found) {
156
- throw new Error(`Timer with id ${id} not found`);
157
- }
158
- }
159
- else {
160
- const timersData = timersRaw.split(/\r?\n/);
161
- let found = false;
162
- for (const timerData of timersData) {
163
- if (!timerData.trim())
164
- continue;
165
- const [timerId] = timerData.split(" ");
166
- if (timerId === id) {
167
- found = true;
168
- continue;
169
- }
170
- newTimersData += timerData + "\n";
171
- }
172
- if (!found) {
173
- throw new Error(`Timer with id ${id} not found`);
174
- }
175
- }
176
- await fs_1.default.promises.writeFile(this.timerfiledir, newTimersData, "utf-8");
177
- return;
178
- }
179
- catch (e) {
180
- throw new Error(`Error when removing timer: ${e}`);
181
- }
182
- }
183
- /**
184
- * @description Starts monitoring expired timers asynchronously and returns immediately. The callback is invoked asynchronously when a timer expires.
185
- * The callback is awaited before continuing.
186
- * @param callback Function invoked when an expired timer is detected (called asynchronously)
187
- * @param interval (number, optional): Check interval in milliseconds (default: 50ms)
188
- * @throws If file operation fails
189
- * @returns (NodeJS.Timeout) intervalId interval id of checkTimers
190
- * @example
191
- * const interval = manager.checkTimers((timer) => {
192
- * console.log(`A timer was stopped: ${timer.id}`);
193
- * });
194
- */
195
- checkTimers(callback, interval = 50) {
196
- return setInterval(async () => {
197
- if (this.checkLock)
198
- return;
199
- this.checkLock = true;
200
- try {
201
- const timersDataRaw = await fs_1.default.promises.readFile(this.timerfiledir, "utf-8");
202
- const timersSet = new Set();
203
- if (this.isJSONLines) {
204
- const timersData = timersDataRaw
205
- .split(/\r?\n/)
206
- .filter(line => line.trim())
207
- .map(line => JSON.parse(line));
208
- for (const timer of timersData) {
209
- timersSet.add(timer);
210
- }
211
- }
212
- else {
213
- const timersData = timersDataRaw.split(/\r?\n/);
214
- for (const timerData of timersData) {
215
- if (!timerData.trim())
216
- continue;
217
- const [id, startStr, stopStr] = timerData.split(" ");
218
- timersSet.add({
219
- id: id,
220
- start: Number(startStr),
221
- stop: Number(stopStr),
222
- });
223
- }
224
- }
225
- const now = Date.now();
226
- for (const timer of timersSet) {
227
- if (Number(timer.stop) <= now) {
228
- await this.removeTimer(timer.id);
229
- await callback(timer);
230
- }
231
- }
232
- }
233
- catch (e) {
234
- throw new Error(`Error when checking alarm: ${e}`);
235
- }
236
- finally {
237
- this.checkLock = false;
238
- }
239
- }, interval);
240
- }
241
- /**
242
- * showTimers
243
- * @description Retrieves all active timers.
244
- * @returns Array of `Timer` objects
245
- * @throws If file operation fails
246
- * @example
247
- * const timers = await manager.showTimers();
248
- * console.log(JSON.stringify(timers))
249
- */
250
- async showTimers() {
251
- try {
252
- const timersRaw = await fs_1.default.promises.readFile(this.timerfiledir, "utf-8");
253
- if (this.isJSONLines) {
254
- const timersData = timersRaw
255
- .split(/\r?\n/)
256
- .filter(t => t.trim())
257
- .map(line => JSON.parse(line));
258
- return timersData;
259
- }
260
- else {
261
- const timersData = timersRaw.split(/\r?\n/);
262
- const timersJSON = [];
263
- for (const timerData of timersData) {
264
- const splitedTimerData = timerData.split(" ");
265
- if (!timerData.trim())
266
- continue;
267
- timersJSON.push({
268
- id: splitedTimerData[0],
269
- start: Number(splitedTimerData[1]),
270
- stop: Number(splitedTimerData[2]),
271
- });
272
- }
273
- return timersJSON;
274
- }
275
- }
276
- catch (e) {
277
- throw new Error(`Error when showing timers: ${e}`);
278
- }
279
- }
280
- }
281
- exports.TimersManager = TimersManager;
3
+ exports.PlainTextTimersManager = exports.JSONLTimersManager = void 0;
4
+ var JSONLTimersManager_js_1 = require("./JSONLTimersManager.cjs");
5
+ Object.defineProperty(exports, "JSONLTimersManager", { enumerable: true, get: function () { return JSONLTimersManager_js_1.JSONLTimersManager; } });
6
+ var PlainTextTimersManager_js_1 = require("./PlainTextTimersManager.cjs");
7
+ Object.defineProperty(exports, "PlainTextTimersManager", { enumerable: true, get: function () { return PlainTextTimersManager_js_1.PlainTextTimersManager; } });
282
8
  //# sourceMappingURL=index.js.map