@hasna/logs 0.3.13 → 0.3.14

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.
@@ -0,0 +1,1241 @@
1
+ // @bun
2
+ import {
3
+ getPage,
4
+ ingestBatch,
5
+ listPages,
6
+ saveSnapshot,
7
+ touchPage
8
+ } from "./index-6zrkek5y.js";
9
+ import {
10
+ createScanRun,
11
+ finishScanRun,
12
+ listJobs,
13
+ updateJob
14
+ } from "./index-3dr7d80h.js";
15
+ import {
16
+ __commonJS,
17
+ __require,
18
+ __toESM
19
+ } from "./index-re3ntm60.js";
20
+
21
+ // node_modules/node-cron/src/task.js
22
+ var require_task = __commonJS((exports, module) => {
23
+ var EventEmitter = __require("events");
24
+
25
+ class Task extends EventEmitter {
26
+ constructor(execution) {
27
+ super();
28
+ if (typeof execution !== "function") {
29
+ throw "execution must be a function";
30
+ }
31
+ this._execution = execution;
32
+ }
33
+ execute(now) {
34
+ let exec;
35
+ try {
36
+ exec = this._execution(now);
37
+ } catch (error) {
38
+ return this.emit("task-failed", error);
39
+ }
40
+ if (exec instanceof Promise) {
41
+ return exec.then(() => this.emit("task-finished")).catch((error) => this.emit("task-failed", error));
42
+ } else {
43
+ this.emit("task-finished");
44
+ return exec;
45
+ }
46
+ }
47
+ }
48
+ module.exports = Task;
49
+ });
50
+
51
+ // node_modules/node-cron/src/convert-expression/month-names-conversion.js
52
+ var require_month_names_conversion = __commonJS((exports, module) => {
53
+ module.exports = (() => {
54
+ const months = [
55
+ "january",
56
+ "february",
57
+ "march",
58
+ "april",
59
+ "may",
60
+ "june",
61
+ "july",
62
+ "august",
63
+ "september",
64
+ "october",
65
+ "november",
66
+ "december"
67
+ ];
68
+ const shortMonths = [
69
+ "jan",
70
+ "feb",
71
+ "mar",
72
+ "apr",
73
+ "may",
74
+ "jun",
75
+ "jul",
76
+ "aug",
77
+ "sep",
78
+ "oct",
79
+ "nov",
80
+ "dec"
81
+ ];
82
+ function convertMonthName(expression, items) {
83
+ for (let i = 0;i < items.length; i++) {
84
+ expression = expression.replace(new RegExp(items[i], "gi"), parseInt(i, 10) + 1);
85
+ }
86
+ return expression;
87
+ }
88
+ function interprete(monthExpression) {
89
+ monthExpression = convertMonthName(monthExpression, months);
90
+ monthExpression = convertMonthName(monthExpression, shortMonths);
91
+ return monthExpression;
92
+ }
93
+ return interprete;
94
+ })();
95
+ });
96
+
97
+ // node_modules/node-cron/src/convert-expression/week-day-names-conversion.js
98
+ var require_week_day_names_conversion = __commonJS((exports, module) => {
99
+ module.exports = (() => {
100
+ const weekDays = [
101
+ "sunday",
102
+ "monday",
103
+ "tuesday",
104
+ "wednesday",
105
+ "thursday",
106
+ "friday",
107
+ "saturday"
108
+ ];
109
+ const shortWeekDays = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
110
+ function convertWeekDayName(expression, items) {
111
+ for (let i = 0;i < items.length; i++) {
112
+ expression = expression.replace(new RegExp(items[i], "gi"), parseInt(i, 10));
113
+ }
114
+ return expression;
115
+ }
116
+ function convertWeekDays(expression) {
117
+ expression = expression.replace("7", "0");
118
+ expression = convertWeekDayName(expression, weekDays);
119
+ return convertWeekDayName(expression, shortWeekDays);
120
+ }
121
+ return convertWeekDays;
122
+ })();
123
+ });
124
+
125
+ // node_modules/node-cron/src/convert-expression/asterisk-to-range-conversion.js
126
+ var require_asterisk_to_range_conversion = __commonJS((exports, module) => {
127
+ module.exports = (() => {
128
+ function convertAsterisk(expression, replecement) {
129
+ if (expression.indexOf("*") !== -1) {
130
+ return expression.replace("*", replecement);
131
+ }
132
+ return expression;
133
+ }
134
+ function convertAsterisksToRanges(expressions) {
135
+ expressions[0] = convertAsterisk(expressions[0], "0-59");
136
+ expressions[1] = convertAsterisk(expressions[1], "0-59");
137
+ expressions[2] = convertAsterisk(expressions[2], "0-23");
138
+ expressions[3] = convertAsterisk(expressions[3], "1-31");
139
+ expressions[4] = convertAsterisk(expressions[4], "1-12");
140
+ expressions[5] = convertAsterisk(expressions[5], "0-6");
141
+ return expressions;
142
+ }
143
+ return convertAsterisksToRanges;
144
+ })();
145
+ });
146
+
147
+ // node_modules/node-cron/src/convert-expression/range-conversion.js
148
+ var require_range_conversion = __commonJS((exports, module) => {
149
+ module.exports = (() => {
150
+ function replaceWithRange(expression, text, init, end) {
151
+ const numbers = [];
152
+ let last = parseInt(end);
153
+ let first = parseInt(init);
154
+ if (first > last) {
155
+ last = parseInt(init);
156
+ first = parseInt(end);
157
+ }
158
+ for (let i = first;i <= last; i++) {
159
+ numbers.push(i);
160
+ }
161
+ return expression.replace(new RegExp(text, "i"), numbers.join());
162
+ }
163
+ function convertRange(expression) {
164
+ const rangeRegEx = /(\d+)-(\d+)/;
165
+ let match = rangeRegEx.exec(expression);
166
+ while (match !== null && match.length > 0) {
167
+ expression = replaceWithRange(expression, match[0], match[1], match[2]);
168
+ match = rangeRegEx.exec(expression);
169
+ }
170
+ return expression;
171
+ }
172
+ function convertAllRanges(expressions) {
173
+ for (let i = 0;i < expressions.length; i++) {
174
+ expressions[i] = convertRange(expressions[i]);
175
+ }
176
+ return expressions;
177
+ }
178
+ return convertAllRanges;
179
+ })();
180
+ });
181
+
182
+ // node_modules/node-cron/src/convert-expression/step-values-conversion.js
183
+ var require_step_values_conversion = __commonJS((exports, module) => {
184
+ module.exports = (() => {
185
+ function convertSteps(expressions) {
186
+ var stepValuePattern = /^(.+)\/(\w+)$/;
187
+ for (var i = 0;i < expressions.length; i++) {
188
+ var match = stepValuePattern.exec(expressions[i]);
189
+ var isStepValue = match !== null && match.length > 0;
190
+ if (isStepValue) {
191
+ var baseDivider = match[2];
192
+ if (isNaN(baseDivider)) {
193
+ throw baseDivider + " is not a valid step value";
194
+ }
195
+ var values = match[1].split(",");
196
+ var stepValues = [];
197
+ var divider = parseInt(baseDivider, 10);
198
+ for (var j = 0;j <= values.length; j++) {
199
+ var value = parseInt(values[j], 10);
200
+ if (value % divider === 0) {
201
+ stepValues.push(value);
202
+ }
203
+ }
204
+ expressions[i] = stepValues.join(",");
205
+ }
206
+ }
207
+ return expressions;
208
+ }
209
+ return convertSteps;
210
+ })();
211
+ });
212
+
213
+ // node_modules/node-cron/src/convert-expression/index.js
214
+ var require_convert_expression = __commonJS((exports, module) => {
215
+ var monthNamesConversion = require_month_names_conversion();
216
+ var weekDayNamesConversion = require_week_day_names_conversion();
217
+ var convertAsterisksToRanges = require_asterisk_to_range_conversion();
218
+ var convertRanges = require_range_conversion();
219
+ var convertSteps = require_step_values_conversion();
220
+ module.exports = (() => {
221
+ function appendSeccondExpression(expressions) {
222
+ if (expressions.length === 5) {
223
+ return ["0"].concat(expressions);
224
+ }
225
+ return expressions;
226
+ }
227
+ function removeSpaces(str) {
228
+ return str.replace(/\s{2,}/g, " ").trim();
229
+ }
230
+ function normalizeIntegers(expressions) {
231
+ for (let i = 0;i < expressions.length; i++) {
232
+ const numbers = expressions[i].split(",");
233
+ for (let j = 0;j < numbers.length; j++) {
234
+ numbers[j] = parseInt(numbers[j]);
235
+ }
236
+ expressions[i] = numbers;
237
+ }
238
+ return expressions;
239
+ }
240
+ function interprete(expression) {
241
+ let expressions = removeSpaces(expression).split(" ");
242
+ expressions = appendSeccondExpression(expressions);
243
+ expressions[4] = monthNamesConversion(expressions[4]);
244
+ expressions[5] = weekDayNamesConversion(expressions[5]);
245
+ expressions = convertAsterisksToRanges(expressions);
246
+ expressions = convertRanges(expressions);
247
+ expressions = convertSteps(expressions);
248
+ expressions = normalizeIntegers(expressions);
249
+ return expressions.join(" ");
250
+ }
251
+ return interprete;
252
+ })();
253
+ });
254
+
255
+ // node_modules/node-cron/src/pattern-validation.js
256
+ var require_pattern_validation = __commonJS((exports, module) => {
257
+ var convertExpression = require_convert_expression();
258
+ var validationRegex = /^(?:\d+|\*|\*\/\d+)$/;
259
+ function isValidExpression(expression, min, max) {
260
+ const options = expression.split(",");
261
+ for (const option of options) {
262
+ const optionAsInt = parseInt(option, 10);
263
+ if (!Number.isNaN(optionAsInt) && (optionAsInt < min || optionAsInt > max) || !validationRegex.test(option))
264
+ return false;
265
+ }
266
+ return true;
267
+ }
268
+ function isInvalidSecond(expression) {
269
+ return !isValidExpression(expression, 0, 59);
270
+ }
271
+ function isInvalidMinute(expression) {
272
+ return !isValidExpression(expression, 0, 59);
273
+ }
274
+ function isInvalidHour(expression) {
275
+ return !isValidExpression(expression, 0, 23);
276
+ }
277
+ function isInvalidDayOfMonth(expression) {
278
+ return !isValidExpression(expression, 1, 31);
279
+ }
280
+ function isInvalidMonth(expression) {
281
+ return !isValidExpression(expression, 1, 12);
282
+ }
283
+ function isInvalidWeekDay(expression) {
284
+ return !isValidExpression(expression, 0, 7);
285
+ }
286
+ function validateFields(patterns, executablePatterns) {
287
+ if (isInvalidSecond(executablePatterns[0]))
288
+ throw new Error(`${patterns[0]} is a invalid expression for second`);
289
+ if (isInvalidMinute(executablePatterns[1]))
290
+ throw new Error(`${patterns[1]} is a invalid expression for minute`);
291
+ if (isInvalidHour(executablePatterns[2]))
292
+ throw new Error(`${patterns[2]} is a invalid expression for hour`);
293
+ if (isInvalidDayOfMonth(executablePatterns[3]))
294
+ throw new Error(`${patterns[3]} is a invalid expression for day of month`);
295
+ if (isInvalidMonth(executablePatterns[4]))
296
+ throw new Error(`${patterns[4]} is a invalid expression for month`);
297
+ if (isInvalidWeekDay(executablePatterns[5]))
298
+ throw new Error(`${patterns[5]} is a invalid expression for week day`);
299
+ }
300
+ function validate(pattern) {
301
+ if (typeof pattern !== "string")
302
+ throw new TypeError("pattern must be a string!");
303
+ const patterns = pattern.split(" ");
304
+ const executablePatterns = convertExpression(pattern).split(" ");
305
+ if (patterns.length === 5)
306
+ patterns.unshift("0");
307
+ validateFields(patterns, executablePatterns);
308
+ }
309
+ module.exports = validate;
310
+ });
311
+
312
+ // node_modules/node-cron/src/time-matcher.js
313
+ var require_time_matcher = __commonJS((exports, module) => {
314
+ var validatePattern = require_pattern_validation();
315
+ var convertExpression = require_convert_expression();
316
+ function matchPattern(pattern, value) {
317
+ if (pattern.indexOf(",") !== -1) {
318
+ const patterns = pattern.split(",");
319
+ return patterns.indexOf(value.toString()) !== -1;
320
+ }
321
+ return pattern === value.toString();
322
+ }
323
+
324
+ class TimeMatcher {
325
+ constructor(pattern, timezone) {
326
+ validatePattern(pattern);
327
+ this.pattern = convertExpression(pattern);
328
+ this.timezone = timezone;
329
+ this.expressions = this.pattern.split(" ");
330
+ this.dtf = this.timezone ? new Intl.DateTimeFormat("en-US", {
331
+ year: "numeric",
332
+ month: "2-digit",
333
+ day: "2-digit",
334
+ hour: "2-digit",
335
+ minute: "2-digit",
336
+ second: "2-digit",
337
+ hourCycle: "h23",
338
+ fractionalSecondDigits: 3,
339
+ timeZone: this.timezone
340
+ }) : null;
341
+ }
342
+ match(date) {
343
+ date = this.apply(date);
344
+ const runOnSecond = matchPattern(this.expressions[0], date.getSeconds());
345
+ const runOnMinute = matchPattern(this.expressions[1], date.getMinutes());
346
+ const runOnHour = matchPattern(this.expressions[2], date.getHours());
347
+ const runOnDay = matchPattern(this.expressions[3], date.getDate());
348
+ const runOnMonth = matchPattern(this.expressions[4], date.getMonth() + 1);
349
+ const runOnWeekDay = matchPattern(this.expressions[5], date.getDay());
350
+ return runOnSecond && runOnMinute && runOnHour && runOnDay && runOnMonth && runOnWeekDay;
351
+ }
352
+ apply(date) {
353
+ if (this.dtf) {
354
+ return new Date(this.dtf.format(date));
355
+ }
356
+ return date;
357
+ }
358
+ }
359
+ module.exports = TimeMatcher;
360
+ });
361
+
362
+ // node_modules/node-cron/src/scheduler.js
363
+ var require_scheduler = __commonJS((exports, module) => {
364
+ var EventEmitter = __require("events");
365
+ var TimeMatcher = require_time_matcher();
366
+
367
+ class Scheduler extends EventEmitter {
368
+ constructor(pattern, timezone, autorecover) {
369
+ super();
370
+ this.timeMatcher = new TimeMatcher(pattern, timezone);
371
+ this.autorecover = autorecover;
372
+ }
373
+ start() {
374
+ this.stop();
375
+ let lastCheck = process.hrtime();
376
+ let lastExecution = this.timeMatcher.apply(new Date);
377
+ const matchTime = () => {
378
+ const delay = 1000;
379
+ const elapsedTime = process.hrtime(lastCheck);
380
+ const elapsedMs = (elapsedTime[0] * 1e9 + elapsedTime[1]) / 1e6;
381
+ const missedExecutions = Math.floor(elapsedMs / 1000);
382
+ for (let i = missedExecutions;i >= 0; i--) {
383
+ const date = new Date(new Date().getTime() - i * 1000);
384
+ let date_tmp = this.timeMatcher.apply(date);
385
+ if (lastExecution.getTime() < date_tmp.getTime() && (i === 0 || this.autorecover) && this.timeMatcher.match(date)) {
386
+ this.emit("scheduled-time-matched", date_tmp);
387
+ date_tmp.setMilliseconds(0);
388
+ lastExecution = date_tmp;
389
+ }
390
+ }
391
+ lastCheck = process.hrtime();
392
+ this.timeout = setTimeout(matchTime, delay);
393
+ };
394
+ matchTime();
395
+ }
396
+ stop() {
397
+ if (this.timeout) {
398
+ clearTimeout(this.timeout);
399
+ }
400
+ this.timeout = null;
401
+ }
402
+ }
403
+ module.exports = Scheduler;
404
+ });
405
+
406
+ // node_modules/uuid/dist/rng.js
407
+ var require_rng = __commonJS((exports) => {
408
+ Object.defineProperty(exports, "__esModule", {
409
+ value: true
410
+ });
411
+ exports.default = rng;
412
+ var _crypto = _interopRequireDefault(__require("crypto"));
413
+ function _interopRequireDefault(obj) {
414
+ return obj && obj.__esModule ? obj : { default: obj };
415
+ }
416
+ var rnds8Pool = new Uint8Array(256);
417
+ var poolPtr = rnds8Pool.length;
418
+ function rng() {
419
+ if (poolPtr > rnds8Pool.length - 16) {
420
+ _crypto.default.randomFillSync(rnds8Pool);
421
+ poolPtr = 0;
422
+ }
423
+ return rnds8Pool.slice(poolPtr, poolPtr += 16);
424
+ }
425
+ });
426
+
427
+ // node_modules/uuid/dist/regex.js
428
+ var require_regex = __commonJS((exports) => {
429
+ Object.defineProperty(exports, "__esModule", {
430
+ value: true
431
+ });
432
+ exports.default = undefined;
433
+ var _default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;
434
+ exports.default = _default;
435
+ });
436
+
437
+ // node_modules/uuid/dist/validate.js
438
+ var require_validate = __commonJS((exports) => {
439
+ Object.defineProperty(exports, "__esModule", {
440
+ value: true
441
+ });
442
+ exports.default = undefined;
443
+ var _regex = _interopRequireDefault(require_regex());
444
+ function _interopRequireDefault(obj) {
445
+ return obj && obj.__esModule ? obj : { default: obj };
446
+ }
447
+ function validate(uuid) {
448
+ return typeof uuid === "string" && _regex.default.test(uuid);
449
+ }
450
+ var _default = validate;
451
+ exports.default = _default;
452
+ });
453
+
454
+ // node_modules/uuid/dist/stringify.js
455
+ var require_stringify = __commonJS((exports) => {
456
+ Object.defineProperty(exports, "__esModule", {
457
+ value: true
458
+ });
459
+ exports.default = undefined;
460
+ var _validate = _interopRequireDefault(require_validate());
461
+ function _interopRequireDefault(obj) {
462
+ return obj && obj.__esModule ? obj : { default: obj };
463
+ }
464
+ var byteToHex = [];
465
+ for (let i = 0;i < 256; ++i) {
466
+ byteToHex.push((i + 256).toString(16).substr(1));
467
+ }
468
+ function stringify(arr, offset = 0) {
469
+ const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
470
+ if (!(0, _validate.default)(uuid)) {
471
+ throw TypeError("Stringified UUID is invalid");
472
+ }
473
+ return uuid;
474
+ }
475
+ var _default = stringify;
476
+ exports.default = _default;
477
+ });
478
+
479
+ // node_modules/uuid/dist/v1.js
480
+ var require_v1 = __commonJS((exports) => {
481
+ Object.defineProperty(exports, "__esModule", {
482
+ value: true
483
+ });
484
+ exports.default = undefined;
485
+ var _rng = _interopRequireDefault(require_rng());
486
+ var _stringify = _interopRequireDefault(require_stringify());
487
+ function _interopRequireDefault(obj) {
488
+ return obj && obj.__esModule ? obj : { default: obj };
489
+ }
490
+ var _nodeId;
491
+ var _clockseq;
492
+ var _lastMSecs = 0;
493
+ var _lastNSecs = 0;
494
+ function v1(options, buf, offset) {
495
+ let i = buf && offset || 0;
496
+ const b = buf || new Array(16);
497
+ options = options || {};
498
+ let node = options.node || _nodeId;
499
+ let clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq;
500
+ if (node == null || clockseq == null) {
501
+ const seedBytes = options.random || (options.rng || _rng.default)();
502
+ if (node == null) {
503
+ node = _nodeId = [seedBytes[0] | 1, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]];
504
+ }
505
+ if (clockseq == null) {
506
+ clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 16383;
507
+ }
508
+ }
509
+ let msecs = options.msecs !== undefined ? options.msecs : Date.now();
510
+ let nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1;
511
+ const dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 1e4;
512
+ if (dt < 0 && options.clockseq === undefined) {
513
+ clockseq = clockseq + 1 & 16383;
514
+ }
515
+ if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {
516
+ nsecs = 0;
517
+ }
518
+ if (nsecs >= 1e4) {
519
+ throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");
520
+ }
521
+ _lastMSecs = msecs;
522
+ _lastNSecs = nsecs;
523
+ _clockseq = clockseq;
524
+ msecs += 12219292800000;
525
+ const tl = ((msecs & 268435455) * 1e4 + nsecs) % 4294967296;
526
+ b[i++] = tl >>> 24 & 255;
527
+ b[i++] = tl >>> 16 & 255;
528
+ b[i++] = tl >>> 8 & 255;
529
+ b[i++] = tl & 255;
530
+ const tmh = msecs / 4294967296 * 1e4 & 268435455;
531
+ b[i++] = tmh >>> 8 & 255;
532
+ b[i++] = tmh & 255;
533
+ b[i++] = tmh >>> 24 & 15 | 16;
534
+ b[i++] = tmh >>> 16 & 255;
535
+ b[i++] = clockseq >>> 8 | 128;
536
+ b[i++] = clockseq & 255;
537
+ for (let n = 0;n < 6; ++n) {
538
+ b[i + n] = node[n];
539
+ }
540
+ return buf || (0, _stringify.default)(b);
541
+ }
542
+ var _default = v1;
543
+ exports.default = _default;
544
+ });
545
+
546
+ // node_modules/uuid/dist/parse.js
547
+ var require_parse = __commonJS((exports) => {
548
+ Object.defineProperty(exports, "__esModule", {
549
+ value: true
550
+ });
551
+ exports.default = undefined;
552
+ var _validate = _interopRequireDefault(require_validate());
553
+ function _interopRequireDefault(obj) {
554
+ return obj && obj.__esModule ? obj : { default: obj };
555
+ }
556
+ function parse(uuid) {
557
+ if (!(0, _validate.default)(uuid)) {
558
+ throw TypeError("Invalid UUID");
559
+ }
560
+ let v;
561
+ const arr = new Uint8Array(16);
562
+ arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24;
563
+ arr[1] = v >>> 16 & 255;
564
+ arr[2] = v >>> 8 & 255;
565
+ arr[3] = v & 255;
566
+ arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8;
567
+ arr[5] = v & 255;
568
+ arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8;
569
+ arr[7] = v & 255;
570
+ arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8;
571
+ arr[9] = v & 255;
572
+ arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 1099511627776 & 255;
573
+ arr[11] = v / 4294967296 & 255;
574
+ arr[12] = v >>> 24 & 255;
575
+ arr[13] = v >>> 16 & 255;
576
+ arr[14] = v >>> 8 & 255;
577
+ arr[15] = v & 255;
578
+ return arr;
579
+ }
580
+ var _default = parse;
581
+ exports.default = _default;
582
+ });
583
+
584
+ // node_modules/uuid/dist/v35.js
585
+ var require_v35 = __commonJS((exports) => {
586
+ Object.defineProperty(exports, "__esModule", {
587
+ value: true
588
+ });
589
+ exports.default = _default;
590
+ exports.URL = exports.DNS = undefined;
591
+ var _stringify = _interopRequireDefault(require_stringify());
592
+ var _parse = _interopRequireDefault(require_parse());
593
+ function _interopRequireDefault(obj) {
594
+ return obj && obj.__esModule ? obj : { default: obj };
595
+ }
596
+ function stringToBytes(str) {
597
+ str = unescape(encodeURIComponent(str));
598
+ const bytes = [];
599
+ for (let i = 0;i < str.length; ++i) {
600
+ bytes.push(str.charCodeAt(i));
601
+ }
602
+ return bytes;
603
+ }
604
+ var DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
605
+ exports.DNS = DNS;
606
+ var URL = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
607
+ exports.URL = URL;
608
+ function _default(name, version, hashfunc) {
609
+ function generateUUID(value, namespace, buf, offset) {
610
+ if (typeof value === "string") {
611
+ value = stringToBytes(value);
612
+ }
613
+ if (typeof namespace === "string") {
614
+ namespace = (0, _parse.default)(namespace);
615
+ }
616
+ if (namespace.length !== 16) {
617
+ throw TypeError("Namespace must be array-like (16 iterable integer values, 0-255)");
618
+ }
619
+ let bytes = new Uint8Array(16 + value.length);
620
+ bytes.set(namespace);
621
+ bytes.set(value, namespace.length);
622
+ bytes = hashfunc(bytes);
623
+ bytes[6] = bytes[6] & 15 | version;
624
+ bytes[8] = bytes[8] & 63 | 128;
625
+ if (buf) {
626
+ offset = offset || 0;
627
+ for (let i = 0;i < 16; ++i) {
628
+ buf[offset + i] = bytes[i];
629
+ }
630
+ return buf;
631
+ }
632
+ return (0, _stringify.default)(bytes);
633
+ }
634
+ try {
635
+ generateUUID.name = name;
636
+ } catch (err) {}
637
+ generateUUID.DNS = DNS;
638
+ generateUUID.URL = URL;
639
+ return generateUUID;
640
+ }
641
+ });
642
+
643
+ // node_modules/uuid/dist/md5.js
644
+ var require_md5 = __commonJS((exports) => {
645
+ Object.defineProperty(exports, "__esModule", {
646
+ value: true
647
+ });
648
+ exports.default = undefined;
649
+ var _crypto = _interopRequireDefault(__require("crypto"));
650
+ function _interopRequireDefault(obj) {
651
+ return obj && obj.__esModule ? obj : { default: obj };
652
+ }
653
+ function md5(bytes) {
654
+ if (Array.isArray(bytes)) {
655
+ bytes = Buffer.from(bytes);
656
+ } else if (typeof bytes === "string") {
657
+ bytes = Buffer.from(bytes, "utf8");
658
+ }
659
+ return _crypto.default.createHash("md5").update(bytes).digest();
660
+ }
661
+ var _default = md5;
662
+ exports.default = _default;
663
+ });
664
+
665
+ // node_modules/uuid/dist/v3.js
666
+ var require_v3 = __commonJS((exports) => {
667
+ Object.defineProperty(exports, "__esModule", {
668
+ value: true
669
+ });
670
+ exports.default = undefined;
671
+ var _v = _interopRequireDefault(require_v35());
672
+ var _md = _interopRequireDefault(require_md5());
673
+ function _interopRequireDefault(obj) {
674
+ return obj && obj.__esModule ? obj : { default: obj };
675
+ }
676
+ var v3 = (0, _v.default)("v3", 48, _md.default);
677
+ var _default = v3;
678
+ exports.default = _default;
679
+ });
680
+
681
+ // node_modules/uuid/dist/v4.js
682
+ var require_v4 = __commonJS((exports) => {
683
+ Object.defineProperty(exports, "__esModule", {
684
+ value: true
685
+ });
686
+ exports.default = undefined;
687
+ var _rng = _interopRequireDefault(require_rng());
688
+ var _stringify = _interopRequireDefault(require_stringify());
689
+ function _interopRequireDefault(obj) {
690
+ return obj && obj.__esModule ? obj : { default: obj };
691
+ }
692
+ function v4(options, buf, offset) {
693
+ options = options || {};
694
+ const rnds = options.random || (options.rng || _rng.default)();
695
+ rnds[6] = rnds[6] & 15 | 64;
696
+ rnds[8] = rnds[8] & 63 | 128;
697
+ if (buf) {
698
+ offset = offset || 0;
699
+ for (let i = 0;i < 16; ++i) {
700
+ buf[offset + i] = rnds[i];
701
+ }
702
+ return buf;
703
+ }
704
+ return (0, _stringify.default)(rnds);
705
+ }
706
+ var _default = v4;
707
+ exports.default = _default;
708
+ });
709
+
710
+ // node_modules/uuid/dist/sha1.js
711
+ var require_sha1 = __commonJS((exports) => {
712
+ Object.defineProperty(exports, "__esModule", {
713
+ value: true
714
+ });
715
+ exports.default = undefined;
716
+ var _crypto = _interopRequireDefault(__require("crypto"));
717
+ function _interopRequireDefault(obj) {
718
+ return obj && obj.__esModule ? obj : { default: obj };
719
+ }
720
+ function sha1(bytes) {
721
+ if (Array.isArray(bytes)) {
722
+ bytes = Buffer.from(bytes);
723
+ } else if (typeof bytes === "string") {
724
+ bytes = Buffer.from(bytes, "utf8");
725
+ }
726
+ return _crypto.default.createHash("sha1").update(bytes).digest();
727
+ }
728
+ var _default = sha1;
729
+ exports.default = _default;
730
+ });
731
+
732
+ // node_modules/uuid/dist/v5.js
733
+ var require_v5 = __commonJS((exports) => {
734
+ Object.defineProperty(exports, "__esModule", {
735
+ value: true
736
+ });
737
+ exports.default = undefined;
738
+ var _v = _interopRequireDefault(require_v35());
739
+ var _sha = _interopRequireDefault(require_sha1());
740
+ function _interopRequireDefault(obj) {
741
+ return obj && obj.__esModule ? obj : { default: obj };
742
+ }
743
+ var v5 = (0, _v.default)("v5", 80, _sha.default);
744
+ var _default = v5;
745
+ exports.default = _default;
746
+ });
747
+
748
+ // node_modules/uuid/dist/nil.js
749
+ var require_nil = __commonJS((exports) => {
750
+ Object.defineProperty(exports, "__esModule", {
751
+ value: true
752
+ });
753
+ exports.default = undefined;
754
+ var _default = "00000000-0000-0000-0000-000000000000";
755
+ exports.default = _default;
756
+ });
757
+
758
+ // node_modules/uuid/dist/version.js
759
+ var require_version = __commonJS((exports) => {
760
+ Object.defineProperty(exports, "__esModule", {
761
+ value: true
762
+ });
763
+ exports.default = undefined;
764
+ var _validate = _interopRequireDefault(require_validate());
765
+ function _interopRequireDefault(obj) {
766
+ return obj && obj.__esModule ? obj : { default: obj };
767
+ }
768
+ function version(uuid) {
769
+ if (!(0, _validate.default)(uuid)) {
770
+ throw TypeError("Invalid UUID");
771
+ }
772
+ return parseInt(uuid.substr(14, 1), 16);
773
+ }
774
+ var _default = version;
775
+ exports.default = _default;
776
+ });
777
+
778
+ // node_modules/uuid/dist/index.js
779
+ var require_dist = __commonJS((exports) => {
780
+ Object.defineProperty(exports, "__esModule", {
781
+ value: true
782
+ });
783
+ Object.defineProperty(exports, "v1", {
784
+ enumerable: true,
785
+ get: function() {
786
+ return _v.default;
787
+ }
788
+ });
789
+ Object.defineProperty(exports, "v3", {
790
+ enumerable: true,
791
+ get: function() {
792
+ return _v2.default;
793
+ }
794
+ });
795
+ Object.defineProperty(exports, "v4", {
796
+ enumerable: true,
797
+ get: function() {
798
+ return _v3.default;
799
+ }
800
+ });
801
+ Object.defineProperty(exports, "v5", {
802
+ enumerable: true,
803
+ get: function() {
804
+ return _v4.default;
805
+ }
806
+ });
807
+ Object.defineProperty(exports, "NIL", {
808
+ enumerable: true,
809
+ get: function() {
810
+ return _nil.default;
811
+ }
812
+ });
813
+ Object.defineProperty(exports, "version", {
814
+ enumerable: true,
815
+ get: function() {
816
+ return _version.default;
817
+ }
818
+ });
819
+ Object.defineProperty(exports, "validate", {
820
+ enumerable: true,
821
+ get: function() {
822
+ return _validate.default;
823
+ }
824
+ });
825
+ Object.defineProperty(exports, "stringify", {
826
+ enumerable: true,
827
+ get: function() {
828
+ return _stringify.default;
829
+ }
830
+ });
831
+ Object.defineProperty(exports, "parse", {
832
+ enumerable: true,
833
+ get: function() {
834
+ return _parse.default;
835
+ }
836
+ });
837
+ var _v = _interopRequireDefault(require_v1());
838
+ var _v2 = _interopRequireDefault(require_v3());
839
+ var _v3 = _interopRequireDefault(require_v4());
840
+ var _v4 = _interopRequireDefault(require_v5());
841
+ var _nil = _interopRequireDefault(require_nil());
842
+ var _version = _interopRequireDefault(require_version());
843
+ var _validate = _interopRequireDefault(require_validate());
844
+ var _stringify = _interopRequireDefault(require_stringify());
845
+ var _parse = _interopRequireDefault(require_parse());
846
+ function _interopRequireDefault(obj) {
847
+ return obj && obj.__esModule ? obj : { default: obj };
848
+ }
849
+ });
850
+
851
+ // node_modules/node-cron/src/scheduled-task.js
852
+ var require_scheduled_task = __commonJS((exports, module) => {
853
+ var EventEmitter = __require("events");
854
+ var Task = require_task();
855
+ var Scheduler = require_scheduler();
856
+ var uuid = require_dist();
857
+
858
+ class ScheduledTask extends EventEmitter {
859
+ constructor(cronExpression, func, options) {
860
+ super();
861
+ if (!options) {
862
+ options = {
863
+ scheduled: true,
864
+ recoverMissedExecutions: false
865
+ };
866
+ }
867
+ this.options = options;
868
+ this.options.name = this.options.name || uuid.v4();
869
+ this._task = new Task(func);
870
+ this._scheduler = new Scheduler(cronExpression, options.timezone, options.recoverMissedExecutions);
871
+ this._scheduler.on("scheduled-time-matched", (now) => {
872
+ this.now(now);
873
+ });
874
+ if (options.scheduled !== false) {
875
+ this._scheduler.start();
876
+ }
877
+ if (options.runOnInit === true) {
878
+ this.now("init");
879
+ }
880
+ }
881
+ now(now = "manual") {
882
+ let result = this._task.execute(now);
883
+ this.emit("task-done", result);
884
+ }
885
+ start() {
886
+ this._scheduler.start();
887
+ }
888
+ stop() {
889
+ this._scheduler.stop();
890
+ }
891
+ }
892
+ module.exports = ScheduledTask;
893
+ });
894
+
895
+ // node_modules/node-cron/src/background-scheduled-task/index.js
896
+ var require_background_scheduled_task = __commonJS((exports, module) => {
897
+ var __dirname = "/Users/hasna/Workspace/hasna/opensource/opensourcedev/open-logs/node_modules/node-cron/src/background-scheduled-task";
898
+ var EventEmitter = __require("events");
899
+ var path = __require("path");
900
+ var { fork } = __require("child_process");
901
+ var uuid = require_dist();
902
+ var daemonPath = `${__dirname}/daemon.js`;
903
+
904
+ class BackgroundScheduledTask extends EventEmitter {
905
+ constructor(cronExpression, taskPath, options) {
906
+ super();
907
+ if (!options) {
908
+ options = {
909
+ scheduled: true,
910
+ recoverMissedExecutions: false
911
+ };
912
+ }
913
+ this.cronExpression = cronExpression;
914
+ this.taskPath = taskPath;
915
+ this.options = options;
916
+ this.options.name = this.options.name || uuid.v4();
917
+ if (options.scheduled) {
918
+ this.start();
919
+ }
920
+ }
921
+ start() {
922
+ this.stop();
923
+ this.forkProcess = fork(daemonPath);
924
+ this.forkProcess.on("message", (message) => {
925
+ switch (message.type) {
926
+ case "task-done":
927
+ this.emit("task-done", message.result);
928
+ break;
929
+ }
930
+ });
931
+ let options = this.options;
932
+ options.scheduled = true;
933
+ this.forkProcess.send({
934
+ type: "register",
935
+ path: path.resolve(this.taskPath),
936
+ cron: this.cronExpression,
937
+ options
938
+ });
939
+ }
940
+ stop() {
941
+ if (this.forkProcess) {
942
+ this.forkProcess.kill();
943
+ }
944
+ }
945
+ pid() {
946
+ if (this.forkProcess) {
947
+ return this.forkProcess.pid;
948
+ }
949
+ }
950
+ isRunning() {
951
+ return !this.forkProcess.killed;
952
+ }
953
+ }
954
+ module.exports = BackgroundScheduledTask;
955
+ });
956
+
957
+ // node_modules/node-cron/src/storage.js
958
+ var require_storage = __commonJS((exports, module) => {
959
+ module.exports = (() => {
960
+ if (!global.scheduledTasks) {
961
+ global.scheduledTasks = new Map;
962
+ }
963
+ return {
964
+ save: (task) => {
965
+ if (!task.options) {
966
+ const uuid = require_dist();
967
+ task.options = {};
968
+ task.options.name = uuid.v4();
969
+ }
970
+ global.scheduledTasks.set(task.options.name, task);
971
+ },
972
+ getTasks: () => {
973
+ return global.scheduledTasks;
974
+ }
975
+ };
976
+ })();
977
+ });
978
+
979
+ // node_modules/node-cron/src/node-cron.js
980
+ var require_node_cron = __commonJS((exports, module) => {
981
+ var ScheduledTask = require_scheduled_task();
982
+ var BackgroundScheduledTask = require_background_scheduled_task();
983
+ var validation = require_pattern_validation();
984
+ var storage = require_storage();
985
+ function schedule(expression, func, options) {
986
+ const task = createTask(expression, func, options);
987
+ storage.save(task);
988
+ return task;
989
+ }
990
+ function createTask(expression, func, options) {
991
+ if (typeof func === "string")
992
+ return new BackgroundScheduledTask(expression, func, options);
993
+ return new ScheduledTask(expression, func, options);
994
+ }
995
+ function validate(expression) {
996
+ try {
997
+ validation(expression);
998
+ return true;
999
+ } catch (_) {
1000
+ return false;
1001
+ }
1002
+ }
1003
+ function getTasks() {
1004
+ return storage.getTasks();
1005
+ }
1006
+ module.exports = { schedule, validate, getTasks };
1007
+ });
1008
+
1009
+ // src/lib/scheduler.ts
1010
+ var import_node_cron = __toESM(require_node_cron(), 1);
1011
+
1012
+ // src/lib/retention.ts
1013
+ var TTL_BY_LEVEL = {
1014
+ debug: "debug_ttl_hours",
1015
+ info: "info_ttl_hours",
1016
+ warn: "warn_ttl_hours",
1017
+ error: "error_ttl_hours",
1018
+ fatal: "error_ttl_hours"
1019
+ };
1020
+ function runRetentionForProject(db, projectId) {
1021
+ const project = db.prepare("SELECT * FROM projects WHERE id = $id").get({ $id: projectId });
1022
+ if (!project)
1023
+ return { deleted: 0 };
1024
+ let deleted = 0;
1025
+ for (const [level, configKey] of Object.entries(TTL_BY_LEVEL)) {
1026
+ const ttlHours = project[configKey];
1027
+ const cutoff = new Date(Date.now() - ttlHours * 3600 * 1000).toISOString();
1028
+ const before = db.prepare("SELECT COUNT(*) as c FROM logs WHERE project_id = $p AND level = $level AND timestamp < $cutoff").get({ $p: projectId, $level: level, $cutoff: cutoff }).c;
1029
+ if (before > 0) {
1030
+ db.prepare("DELETE FROM logs WHERE project_id = $p AND level = $level AND timestamp < $cutoff").run({ $p: projectId, $level: level, $cutoff: cutoff });
1031
+ deleted += before;
1032
+ }
1033
+ }
1034
+ const total = db.prepare("SELECT COUNT(*) as c FROM logs WHERE project_id = $p").get({ $p: projectId }).c;
1035
+ if (total > project.max_rows) {
1036
+ const toDelete = total - project.max_rows;
1037
+ db.prepare(`DELETE FROM logs WHERE id IN (SELECT id FROM logs WHERE project_id = $p ORDER BY timestamp ASC LIMIT ${toDelete})`).run({ $p: projectId });
1038
+ deleted += toDelete;
1039
+ }
1040
+ return { deleted };
1041
+ }
1042
+ function runRetentionAll(db) {
1043
+ const projects = db.prepare("SELECT id FROM projects").all();
1044
+ let deleted = 0;
1045
+ for (const p of projects) {
1046
+ deleted += runRetentionForProject(db, p.id).deleted;
1047
+ }
1048
+ return { deleted, projects: projects.length };
1049
+ }
1050
+ function setRetentionPolicy(db, projectId, config) {
1051
+ const fields = Object.keys(config).map((k) => `${k} = $${k}`).join(", ");
1052
+ if (!fields)
1053
+ return;
1054
+ const params = Object.fromEntries(Object.entries(config).map(([k, v]) => [`$${k}`, v]));
1055
+ params.$id = projectId;
1056
+ db.prepare(`UPDATE projects SET ${fields} WHERE id = $id`).run(params);
1057
+ }
1058
+
1059
+ // src/lib/page-auth.ts
1060
+ import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
1061
+ var SECRET_KEY = Buffer.from((process.env.LOGS_SECRET_KEY ?? "open-logs-default-key-32bytesXXX").padEnd(32).slice(0, 32));
1062
+ function encrypt(text) {
1063
+ const iv = randomBytes(16);
1064
+ const cipher = createCipheriv("aes-256-cbc", SECRET_KEY, iv);
1065
+ const encrypted = Buffer.concat([cipher.update(text, "utf8"), cipher.final()]);
1066
+ return iv.toString("hex") + ":" + encrypted.toString("hex");
1067
+ }
1068
+ function decrypt(text) {
1069
+ const [ivHex, encHex] = text.split(":");
1070
+ if (!ivHex || !encHex)
1071
+ return text;
1072
+ const iv = Buffer.from(ivHex, "hex");
1073
+ const enc = Buffer.from(encHex, "hex");
1074
+ const decipher = createDecipheriv("aes-256-cbc", SECRET_KEY, iv);
1075
+ return Buffer.concat([decipher.update(enc), decipher.final()]).toString("utf8");
1076
+ }
1077
+ function setPageAuth(db, pageId, type, credentials) {
1078
+ const encrypted = encrypt(credentials);
1079
+ return db.prepare(`
1080
+ INSERT INTO page_auth (page_id, type, credentials)
1081
+ VALUES ($page_id, $type, $credentials)
1082
+ ON CONFLICT(page_id) DO UPDATE SET type = excluded.type, credentials = excluded.credentials
1083
+ RETURNING *
1084
+ `).get({ $page_id: pageId, $type: type, $credentials: encrypted });
1085
+ }
1086
+ function getPageAuth(db, pageId) {
1087
+ const row = db.prepare("SELECT * FROM page_auth WHERE page_id = $id").get({ $id: pageId });
1088
+ if (!row)
1089
+ return null;
1090
+ return { type: row.type, credentials: decrypt(row.credentials) };
1091
+ }
1092
+ function deletePageAuth(db, pageId) {
1093
+ db.run("DELETE FROM page_auth WHERE page_id = $id", { $id: pageId });
1094
+ }
1095
+
1096
+ // src/lib/scanner.ts
1097
+ async function scanPage(db, projectId, pageId, urlOverride) {
1098
+ const page = getPage(db, pageId);
1099
+ const url = urlOverride || page?.url;
1100
+ if (!url)
1101
+ throw new Error(`No URL for page ${pageId}`);
1102
+ const { chromium } = await import("playwright");
1103
+ const browser = await chromium.launch({ headless: true });
1104
+ const auth = getPageAuth(db, pageId);
1105
+ const contextOptions = {
1106
+ userAgent: "Mozilla/5.0 (@hasna/logs scanner) AppleWebKit/537.36"
1107
+ };
1108
+ if (auth?.type === "cookie") {
1109
+ try {
1110
+ contextOptions.storageState = JSON.parse(auth.credentials);
1111
+ } catch {}
1112
+ } else if (auth?.type === "basic") {
1113
+ const [username, password] = auth.credentials.split(":");
1114
+ contextOptions.httpCredentials = { username: username ?? "", password: password ?? "" };
1115
+ }
1116
+ const context = await browser.newContext(contextOptions);
1117
+ if (auth?.type === "bearer") {
1118
+ await context.route("**/*", (route) => {
1119
+ route.continue({ headers: { ...route.request().headers(), Authorization: `Bearer ${auth.credentials}` } });
1120
+ });
1121
+ }
1122
+ const browserPage = await context.newPage();
1123
+ const collected = [];
1124
+ let errorsFound = 0;
1125
+ browserPage.on("console", (msg) => {
1126
+ const level = msg.type() === "error" ? "error" : msg.type() === "warning" ? "warn" : msg.type() === "info" ? "info" : "debug";
1127
+ if (level === "error")
1128
+ errorsFound++;
1129
+ collected.push({
1130
+ project_id: projectId,
1131
+ page_id: pageId,
1132
+ level,
1133
+ source: "scanner",
1134
+ message: msg.text(),
1135
+ url
1136
+ });
1137
+ });
1138
+ browserPage.on("pageerror", (err) => {
1139
+ errorsFound++;
1140
+ collected.push({
1141
+ project_id: projectId,
1142
+ page_id: pageId,
1143
+ level: "error",
1144
+ source: "scanner",
1145
+ message: err.message,
1146
+ stack_trace: err.stack,
1147
+ url
1148
+ });
1149
+ });
1150
+ browserPage.on("requestfailed", (req) => {
1151
+ collected.push({
1152
+ project_id: projectId,
1153
+ page_id: pageId,
1154
+ level: "warn",
1155
+ source: "scanner",
1156
+ message: `Network request failed: ${req.url()} \u2014 ${req.failure()?.errorText ?? "unknown"}`,
1157
+ url
1158
+ });
1159
+ });
1160
+ let perfScore = null;
1161
+ try {
1162
+ await browserPage.goto(url, { waitUntil: "networkidle", timeout: 30000 });
1163
+ try {
1164
+ const metrics = await browserPage.evaluate(() => {
1165
+ const nav = performance.getEntriesByType("navigation")[0];
1166
+ const paint = performance.getEntriesByName("first-contentful-paint")[0];
1167
+ return {
1168
+ ttfb: nav ? nav.responseStart - nav.requestStart : null,
1169
+ fcp: paint?.startTime ?? null,
1170
+ domLoad: nav ? nav.domContentLoadedEventEnd - nav.startTime : null
1171
+ };
1172
+ });
1173
+ if (metrics.fcp !== null || metrics.ttfb !== null) {
1174
+ saveSnapshot(db, {
1175
+ project_id: projectId,
1176
+ page_id: pageId,
1177
+ url,
1178
+ fcp: metrics.fcp,
1179
+ ttfb: metrics.ttfb,
1180
+ lcp: null,
1181
+ cls: null,
1182
+ tti: metrics.domLoad,
1183
+ score: null,
1184
+ raw_audit: JSON.stringify(metrics)
1185
+ });
1186
+ }
1187
+ } catch {}
1188
+ } finally {
1189
+ await browser.close();
1190
+ }
1191
+ if (collected.length > 0) {
1192
+ ingestBatch(db, collected);
1193
+ if (page)
1194
+ touchPage(db, pageId);
1195
+ }
1196
+ return { logsCollected: collected.length, errorsFound, perfScore };
1197
+ }
1198
+
1199
+ // src/lib/scheduler.ts
1200
+ var tasks = new Map;
1201
+ function startScheduler(db) {
1202
+ const jobs = listJobs(db).filter((j) => j.enabled);
1203
+ for (const job of jobs) {
1204
+ scheduleJob(db, job.id, job.schedule, job.project_id, job.page_id ?? undefined);
1205
+ }
1206
+ import_node_cron.default.schedule("0 * * * *", () => {
1207
+ const result = runRetentionAll(db);
1208
+ if (result.deleted > 0)
1209
+ console.log(`Retention: deleted ${result.deleted} logs across ${result.projects} project(s)`);
1210
+ });
1211
+ console.log(`Scheduler started: ${tasks.size} job(s) active`);
1212
+ }
1213
+ function scheduleJob(db, jobId, schedule, projectId, pageId) {
1214
+ if (tasks.has(jobId))
1215
+ tasks.get(jobId).stop();
1216
+ const task = import_node_cron.default.schedule(schedule, async () => {
1217
+ await runJob(db, jobId, projectId, pageId);
1218
+ });
1219
+ tasks.set(jobId, task);
1220
+ }
1221
+ async function runJob(db, jobId, projectId, pageId) {
1222
+ const pages = pageId ? [{ id: pageId, url: "" }] : listPages(db, projectId);
1223
+ await Promise.all(pages.map(async (page) => {
1224
+ const run = createScanRun(db, { job_id: jobId, page_id: page.id });
1225
+ try {
1226
+ const result = await scanPage(db, projectId, page.id, page.url);
1227
+ finishScanRun(db, run.id, {
1228
+ status: "completed",
1229
+ logs_collected: result.logsCollected,
1230
+ errors_found: result.errorsFound,
1231
+ perf_score: result.perfScore ?? undefined
1232
+ });
1233
+ } catch (err) {
1234
+ finishScanRun(db, run.id, { status: "failed", logs_collected: 0, errors_found: 0 });
1235
+ console.error(`Scan failed for page ${page.id}:`, err);
1236
+ }
1237
+ }));
1238
+ updateJob(db, jobId, { last_run_at: new Date().toISOString() });
1239
+ }
1240
+
1241
+ export { runRetentionForProject, setRetentionPolicy, setPageAuth, deletePageAuth, startScheduler, runJob };