asaihost-nodejs 0.0.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 (76) hide show
  1. package/README.md +518 -0
  2. package/dist/InterventionLog-25EHE4QR.cjs +30 -0
  3. package/dist/InterventionLog-25EHE4QR.cjs.map +1 -0
  4. package/dist/InterventionLog-R6CCPU2B.es.js +30 -0
  5. package/dist/InterventionLog-R6CCPU2B.es.js.map +1 -0
  6. package/dist/LogStore-ECXX34WC.es.js +54 -0
  7. package/dist/LogStore-ECXX34WC.es.js.map +1 -0
  8. package/dist/LogStore-M2AUBNGO.cjs +54 -0
  9. package/dist/LogStore-M2AUBNGO.cjs.map +1 -0
  10. package/dist/asaihost-nodejs.cjs +6761 -0
  11. package/dist/asaihost-nodejs.cjs.map +1 -0
  12. package/dist/asaihost-nodejs.d.cts +406 -0
  13. package/dist/asaihost-nodejs.d.ts +406 -0
  14. package/dist/asaihost-nodejs.es.js +6761 -0
  15. package/dist/asaihost-nodejs.es.js.map +1 -0
  16. package/dist/chunk-4WJDC4M4.es.js +311 -0
  17. package/dist/chunk-4WJDC4M4.es.js.map +1 -0
  18. package/dist/chunk-6U2I5EON.es.js +12 -0
  19. package/dist/chunk-6U2I5EON.es.js.map +1 -0
  20. package/dist/chunk-DROOHKB3.es.js +87 -0
  21. package/dist/chunk-DROOHKB3.es.js.map +1 -0
  22. package/dist/chunk-E7V3EBDB.es.js +435 -0
  23. package/dist/chunk-E7V3EBDB.es.js.map +1 -0
  24. package/dist/chunk-EOGZPRML.es.js +740 -0
  25. package/dist/chunk-EOGZPRML.es.js.map +1 -0
  26. package/dist/chunk-G4WVDUBH.cjs +463 -0
  27. package/dist/chunk-G4WVDUBH.cjs.map +1 -0
  28. package/dist/chunk-HHPGUJ75.cjs +162 -0
  29. package/dist/chunk-HHPGUJ75.cjs.map +1 -0
  30. package/dist/chunk-KOFCBB3N.cjs +87 -0
  31. package/dist/chunk-KOFCBB3N.cjs.map +1 -0
  32. package/dist/chunk-KUZQ36IJ.es.js +162 -0
  33. package/dist/chunk-KUZQ36IJ.es.js.map +1 -0
  34. package/dist/chunk-LOMSUPPU.es.js +1202 -0
  35. package/dist/chunk-LOMSUPPU.es.js.map +1 -0
  36. package/dist/chunk-MCMADJQR.es.js +463 -0
  37. package/dist/chunk-MCMADJQR.es.js.map +1 -0
  38. package/dist/chunk-NLBFIRDB.cjs +105 -0
  39. package/dist/chunk-NLBFIRDB.cjs.map +1 -0
  40. package/dist/chunk-O6LVLSNB.cjs +40 -0
  41. package/dist/chunk-O6LVLSNB.cjs.map +1 -0
  42. package/dist/chunk-QWVR2HNT.cjs +435 -0
  43. package/dist/chunk-QWVR2HNT.cjs.map +1 -0
  44. package/dist/chunk-SMVZ3ZDJ.cjs +12 -0
  45. package/dist/chunk-SMVZ3ZDJ.cjs.map +1 -0
  46. package/dist/chunk-UTKVJE7N.es.js +40 -0
  47. package/dist/chunk-UTKVJE7N.es.js.map +1 -0
  48. package/dist/chunk-VLMM735Q.cjs +1202 -0
  49. package/dist/chunk-VLMM735Q.cjs.map +1 -0
  50. package/dist/chunk-W7DVKGX5.cjs +311 -0
  51. package/dist/chunk-W7DVKGX5.cjs.map +1 -0
  52. package/dist/chunk-X7VHW2TD.cjs +740 -0
  53. package/dist/chunk-X7VHW2TD.cjs.map +1 -0
  54. package/dist/chunk-XBIN4C2V.es.js +105 -0
  55. package/dist/chunk-XBIN4C2V.es.js.map +1 -0
  56. package/dist/intervention-hooks-FI4EHOL5.es.js +21 -0
  57. package/dist/intervention-hooks-FI4EHOL5.es.js.map +1 -0
  58. package/dist/intervention-hooks-LE6X4C6N.cjs +21 -0
  59. package/dist/intervention-hooks-LE6X4C6N.cjs.map +1 -0
  60. package/dist/log-alert-GLCULMQP.es.js +51 -0
  61. package/dist/log-alert-GLCULMQP.es.js.map +1 -0
  62. package/dist/log-alert-LAJ6VSAG.cjs +51 -0
  63. package/dist/log-alert-LAJ6VSAG.cjs.map +1 -0
  64. package/dist/log-formats-FKFMQKNO.cjs +31 -0
  65. package/dist/log-formats-FKFMQKNO.cjs.map +1 -0
  66. package/dist/log-formats-I5E32H5F.es.js +31 -0
  67. package/dist/log-formats-I5E32H5F.es.js.map +1 -0
  68. package/dist/password-63OY27RX.es.js +20 -0
  69. package/dist/password-63OY27RX.es.js.map +1 -0
  70. package/dist/password-NZ5EGDWG.cjs +20 -0
  71. package/dist/password-NZ5EGDWG.cjs.map +1 -0
  72. package/dist/user-store-J7LWEXSW.es.js +12 -0
  73. package/dist/user-store-J7LWEXSW.es.js.map +1 -0
  74. package/dist/user-store-SX4N6PQ4.cjs +12 -0
  75. package/dist/user-store-SX4N6PQ4.cjs.map +1 -0
  76. package/package.json +79 -0
@@ -0,0 +1,1202 @@
1
+ import {
2
+ getNowTime
3
+ } from "./chunk-UTKVJE7N.es.js";
4
+ import {
5
+ asRows,
6
+ getDataServer,
7
+ normalizeStoreOpt,
8
+ qNum,
9
+ qStr,
10
+ resolveStoreConfig
11
+ } from "./chunk-KUZQ36IJ.es.js";
12
+ import {
13
+ __export,
14
+ __name
15
+ } from "./chunk-6U2I5EON.es.js";
16
+
17
+ // src/sysserver/lib/common/LogStore.ts
18
+ var LogStore_exports = {};
19
+ __export(LogStore_exports, {
20
+ archiveInterventionYear: () => archiveInterventionYear,
21
+ exportLogContent: () => exportLogContent,
22
+ getComplianceReport: () => getComplianceReport,
23
+ getEffectiveStoreType: () => getEffectiveStoreType,
24
+ getLogStoreConfig: () => getLogStoreConfig,
25
+ getLogStoreMeta: () => getLogStoreMeta,
26
+ getUnifiedEntry: () => getUnifiedEntry,
27
+ getUnifiedStats: () => getUnifiedStats,
28
+ groupsToInterventionFiles: () => groupsToInterventionFiles,
29
+ groupsToManageChildren: () => groupsToManageChildren,
30
+ isLogStoreEnabled: () => isLogStoreEnabled,
31
+ isLogStoreFileBackend: () => isLogStoreFileBackend,
32
+ isLogStoreSqlite: () => isLogStoreSqlite,
33
+ listUnifiedGroups: () => listUnifiedGroups,
34
+ mirrorAccessLog: () => mirrorAccessLog,
35
+ mirrorInterventionLog: () => mirrorInterventionLog,
36
+ mirrorWebLog: () => mirrorWebLog,
37
+ prefersDiskLogAccess: () => prefersDiskLogAccess,
38
+ purgeSqliteEntriesForFile: () => purgeSqliteEntriesForFile,
39
+ purgeStoreEntriesForFile: () => purgeStoreEntriesForFile,
40
+ queryUnifiedLogs: () => queryUnifiedLogs,
41
+ readWebLogFromStore: () => readWebLogFromStore,
42
+ searchUnifiedLogs: () => searchUnifiedLogs
43
+ });
44
+
45
+ // src/sysserver/lib/common/log-file-store.ts
46
+ import fs from "fs/promises";
47
+ import path from "path";
48
+ function storeBaseAbs($asai) {
49
+ const resolved = resolveStoreConfig($asai, "log");
50
+ const opt = normalizeStoreOpt("log", resolved.type, resolved.opt);
51
+ const dir = String(opt.dir || "webdata/webdb/log/store/");
52
+ return path.resolve(process.cwd(), dir);
53
+ }
54
+ __name(storeBaseAbs, "storeBaseAbs");
55
+ var INDEX_ROOT = "index";
56
+ var META_ROOT = "_meta";
57
+ var ID_COUNTER = "id-counter.json";
58
+ var LEGACY_BLOB = "log_entries.json";
59
+ function indexRootAbs($asai) {
60
+ return path.join(storeBaseAbs($asai), INDEX_ROOT);
61
+ }
62
+ __name(indexRootAbs, "indexRootAbs");
63
+ function safeSeg(v) {
64
+ return (v || "_").replace(/[\\/:*?"<>|]/g, "_").slice(0, 64) || "_";
65
+ }
66
+ __name(safeSeg, "safeSeg");
67
+ function entryRelPath(row) {
68
+ const kind = safeSeg(String(row.kind || "web"));
69
+ const ns = safeSeg(String(row.ns || "_"));
70
+ const source = safeSeg(String(row.source || "_"));
71
+ const logDate = safeSeg(String(row.log_date || "unknown"));
72
+ const id = String(row.id ?? "0");
73
+ return path.join(INDEX_ROOT, kind, ns, source, logDate, `${id}.json`);
74
+ }
75
+ __name(entryRelPath, "entryRelPath");
76
+ function rowToRecord(row) {
77
+ const out = { ...row };
78
+ for (const k of ["severity", "retention_protected", "created_at", "id"]) {
79
+ if (out[k] != null && out[k] !== "") out[k] = Number(out[k]);
80
+ }
81
+ return out;
82
+ }
83
+ __name(rowToRecord, "rowToRecord");
84
+ async function ensureDir(dir) {
85
+ await fs.mkdir(dir, { recursive: true });
86
+ }
87
+ __name(ensureDir, "ensureDir");
88
+ async function readCounter($asai) {
89
+ const file = path.join(storeBaseAbs($asai), META_ROOT, ID_COUNTER);
90
+ try {
91
+ const raw = await fs.readFile(file, "utf8");
92
+ const parsed = JSON.parse(raw);
93
+ return Math.max(0, Number(parsed.next || parsed.last || 0));
94
+ } catch {
95
+ return 0;
96
+ }
97
+ }
98
+ __name(readCounter, "readCounter");
99
+ async function writeCounter($asai, next) {
100
+ const dir = path.join(storeBaseAbs($asai), META_ROOT);
101
+ await ensureDir(dir);
102
+ await fs.writeFile(path.join(dir, ID_COUNTER), JSON.stringify({ next, updatedAt: Date.now() }, null, 2), "utf8");
103
+ }
104
+ __name(writeCounter, "writeCounter");
105
+ async function nextId($asai) {
106
+ const cur = await readCounter($asai);
107
+ const id = cur + 1;
108
+ await writeCounter($asai, id);
109
+ return id;
110
+ }
111
+ __name(nextId, "nextId");
112
+ async function migrateLegacyBlobIfNeeded($asai) {
113
+ const base = storeBaseAbs($asai);
114
+ const legacyPath = path.join(base, LEGACY_BLOB);
115
+ let legacy = [];
116
+ try {
117
+ const raw = await fs.readFile(legacyPath, "utf8");
118
+ const parsed = JSON.parse(raw);
119
+ if (Array.isArray(parsed) && parsed.length) legacy = parsed;
120
+ } catch {
121
+ return 0;
122
+ }
123
+ let maxId = await readCounter($asai);
124
+ for (const row of legacy) {
125
+ const id = Number(row.id || ++maxId);
126
+ if (id > maxId) maxId = id;
127
+ const record = rowToRecord({ ...row, id });
128
+ const abs = path.join(base, entryRelPath(record));
129
+ await ensureDir(path.dirname(abs));
130
+ await fs.writeFile(abs, JSON.stringify(record, null, 2), "utf8");
131
+ }
132
+ await writeCounter($asai, maxId);
133
+ await fs.rename(legacyPath, `${legacyPath}.migrated.${Date.now()}`).catch(() => void 0);
134
+ return legacy.length;
135
+ }
136
+ __name(migrateLegacyBlobIfNeeded, "migrateLegacyBlobIfNeeded");
137
+ async function walkIndexFiles($asai) {
138
+ const root = indexRootAbs($asai);
139
+ const rows = [];
140
+ async function walk(dir) {
141
+ let entries;
142
+ try {
143
+ entries = await fs.readdir(dir, { withFileTypes: true });
144
+ } catch {
145
+ return;
146
+ }
147
+ for (const ent of entries) {
148
+ const full = path.join(dir, ent.name);
149
+ if (ent.isDirectory()) {
150
+ await walk(full);
151
+ } else if (ent.isFile() && ent.name.endsWith(".json")) {
152
+ try {
153
+ const raw = await fs.readFile(full, "utf8");
154
+ const parsed = JSON.parse(raw);
155
+ if (parsed && typeof parsed === "object") rows.push(rowToRecord(parsed));
156
+ } catch {
157
+ }
158
+ }
159
+ }
160
+ }
161
+ __name(walk, "walk");
162
+ await walk(root);
163
+ return rows;
164
+ }
165
+ __name(walkIndexFiles, "walkIndexFiles");
166
+ function applyQueryFilter(rows, filter) {
167
+ let out = rows;
168
+ if (filter.kind) out = out.filter((r) => r.kind === filter.kind);
169
+ if (filter.ns) out = out.filter((r) => r.ns === filter.ns);
170
+ if (filter.source) out = out.filter((r) => r.source === filter.source);
171
+ if (filter.log_date) out = out.filter((r) => r.log_date === filter.log_date);
172
+ if (filter.file_name) out = out.filter((r) => r.file_name === filter.file_name);
173
+ out.sort((a, b) => Number(b.created_at || 0) - Number(a.created_at || 0));
174
+ if (filter.limit != null) out = out.slice(0, filter.limit);
175
+ return out;
176
+ }
177
+ __name(applyQueryFilter, "applyQueryFilter");
178
+ function applySearchFilters(rows, filter) {
179
+ let out = rows;
180
+ if (filter.keyword) {
181
+ const kw = filter.keyword.toLowerCase();
182
+ out = out.filter((r) => {
183
+ const hay = [r.message, r.raw_line, r.event_type, r.us, r.identification, r.category].map((v) => String(v || "").toLowerCase()).join(" ");
184
+ return hay.includes(kw);
185
+ });
186
+ }
187
+ if (filter.event_type) {
188
+ const et = filter.event_type.toUpperCase();
189
+ out = out.filter((r) => String(r.event_type || "").toUpperCase() === et);
190
+ }
191
+ if (filter.severity_min != null && !Number.isNaN(Number(filter.severity_min))) {
192
+ const min = Number(filter.severity_min);
193
+ out = out.filter((r) => Number(r.severity || 0) >= min);
194
+ }
195
+ if (filter.date_from) out = out.filter((r) => String(r.log_date || "") >= filter.date_from);
196
+ if (filter.date_to) out = out.filter((r) => String(r.log_date || "") <= filter.date_to);
197
+ if (filter.outcome) {
198
+ const oc = filter.outcome.toLowerCase();
199
+ out = out.filter((r) => String(r.outcome || "").toLowerCase() === oc);
200
+ }
201
+ return out;
202
+ }
203
+ __name(applySearchFilters, "applySearchFilters");
204
+ var migrateOnce = null;
205
+ async function ensureMigrated($asai) {
206
+ if (!migrateOnce) {
207
+ migrateOnce = migrateLegacyBlobIfNeeded($asai).then(() => void 0);
208
+ }
209
+ await migrateOnce;
210
+ }
211
+ __name(ensureMigrated, "ensureMigrated");
212
+ async function fileStoreInsert($asai, row) {
213
+ await ensureMigrated($asai);
214
+ const id = await nextId($asai);
215
+ const record = rowToRecord({ id, ...row });
216
+ const abs = path.join(storeBaseAbs($asai), entryRelPath(record));
217
+ await ensureDir(path.dirname(abs));
218
+ await fs.writeFile(abs, JSON.stringify(record, null, 2), "utf8");
219
+ }
220
+ __name(fileStoreInsert, "fileStoreInsert");
221
+ async function fileStoreQuery($asai, filter = {}) {
222
+ await ensureMigrated($asai);
223
+ const rows = await walkIndexFiles($asai);
224
+ return applyQueryFilter(rows, { ...filter, limit: filter.limit ?? 500 });
225
+ }
226
+ __name(fileStoreQuery, "fileStoreQuery");
227
+ async function fileStoreGet($asai, id) {
228
+ await ensureMigrated($asai);
229
+ const rows = await walkIndexFiles($asai);
230
+ const found = rows.find((r) => String(r.id) === String(id));
231
+ return found ? rowToRecord(found) : null;
232
+ }
233
+ __name(fileStoreGet, "fileStoreGet");
234
+ async function fileStoreSearch($asai, filter = {}) {
235
+ await ensureMigrated($asai);
236
+ const baseLimit = 2e4;
237
+ const rows = await fileStoreQuery($asai, {
238
+ kind: filter.kind,
239
+ ns: filter.ns,
240
+ source: filter.source,
241
+ log_date: filter.log_date,
242
+ file_name: filter.file_name,
243
+ limit: baseLimit
244
+ });
245
+ const filtered = applySearchFilters(rows, filter);
246
+ const offset = Math.max(0, Number(filter.offset) || 0);
247
+ const limit = Math.min(2e3, Math.max(1, Number(filter.limit) || 200));
248
+ return {
249
+ entries: filtered.slice(offset, offset + limit),
250
+ total: filtered.length,
251
+ truncated: rows.length >= baseLimit
252
+ };
253
+ }
254
+ __name(fileStoreSearch, "fileStoreSearch");
255
+ async function fileStoreStats($asai) {
256
+ await ensureMigrated($asai);
257
+ const rows = await walkIndexFiles($asai);
258
+ const stats = { total: rows.length, web: 0, intervention: 0, sec: 0, access: 0, prod: 0, test: 0 };
259
+ for (const r of rows) {
260
+ const k = String(r.kind || "");
261
+ if (k === "web") stats.web += 1;
262
+ else if (k === "intervention") stats.intervention += 1;
263
+ else if (k === "sec") stats.sec += 1;
264
+ else if (k === "access") stats.access += 1;
265
+ const ns = String(r.ns || "");
266
+ if (ns === "prod") stats.prod += 1;
267
+ if (ns === "test") stats.test += 1;
268
+ }
269
+ return stats;
270
+ }
271
+ __name(fileStoreStats, "fileStoreStats");
272
+ async function fileStoreDeleteByFile($asai, fileName, ns = "") {
273
+ await ensureMigrated($asai);
274
+ const base = storeBaseAbs($asai);
275
+ const root = indexRootAbs($asai);
276
+ let removed = 0;
277
+ async function walk(dir) {
278
+ let entries;
279
+ try {
280
+ entries = await fs.readdir(dir, { withFileTypes: true });
281
+ } catch {
282
+ return;
283
+ }
284
+ for (const ent of entries) {
285
+ const full = path.join(dir, ent.name);
286
+ if (ent.isDirectory()) {
287
+ await walk(full);
288
+ } else if (ent.isFile() && ent.name.endsWith(".json")) {
289
+ try {
290
+ const raw = await fs.readFile(full, "utf8");
291
+ const parsed = JSON.parse(raw);
292
+ if (String(parsed.file_name) !== fileName) continue;
293
+ if (ns && String(parsed.ns) !== ns) continue;
294
+ await fs.unlink(full);
295
+ removed += 1;
296
+ } catch {
297
+ }
298
+ }
299
+ }
300
+ }
301
+ __name(walk, "walk");
302
+ await walk(root);
303
+ return removed;
304
+ }
305
+ __name(fileStoreDeleteByFile, "fileStoreDeleteByFile");
306
+ async function fileStoreDiskStats($asai) {
307
+ const logger = $asai?.hostconfig?.logger || {};
308
+ const scanDirs = [
309
+ { kind: "web", dir: logger.path?.server },
310
+ { kind: "web", dir: logger.path?.client },
311
+ { kind: "access", dir: logger.path?.access },
312
+ { kind: "intervention", dir: logger.intervention?.path, ns: "prod" },
313
+ { kind: "intervention", dir: logger.intervention?.testPath, ns: "test" }
314
+ ].filter((d) => d.dir);
315
+ const stats = { total: 0, web: 0, intervention: 0, sec: 0, access: 0, prod: 0, test: 0 };
316
+ for (const { kind, dir, ns } of scanDirs) {
317
+ let count = 0;
318
+ try {
319
+ const entries = await fs.readdir(String(dir), { withFileTypes: true });
320
+ for (const ent of entries) {
321
+ if (!ent.isFile()) continue;
322
+ if (ent.name.endsWith(".delete") || ent.name.startsWith(".")) continue;
323
+ count += 1;
324
+ }
325
+ } catch {
326
+ continue;
327
+ }
328
+ if (kind === "web") stats.web += count;
329
+ else if (kind === "intervention") stats.intervention += count;
330
+ else if (kind === "access") stats.access += count;
331
+ if (ns === "prod") stats.prod += count;
332
+ if (ns === "test") stats.test += count;
333
+ stats.total += count;
334
+ }
335
+ const indexStats = await fileStoreStats($asai).catch(() => ({ sec: 0 }));
336
+ stats.sec = indexStats.sec || 0;
337
+ return stats;
338
+ }
339
+ __name(fileStoreDiskStats, "fileStoreDiskStats");
340
+ function getFileStorePaths($asai) {
341
+ const base = storeBaseAbs($asai);
342
+ return { base, index: path.join(base, INDEX_ROOT) };
343
+ }
344
+ __name(getFileStorePaths, "getFileStorePaths");
345
+
346
+ // src/sysserver/lib/common/log-db.ts
347
+ var LOG_ENTRY_FIELDS = [
348
+ "kind",
349
+ "ns",
350
+ "source",
351
+ "log_date",
352
+ "file_name",
353
+ "event_type",
354
+ "category",
355
+ "severity",
356
+ "us",
357
+ "message",
358
+ "raw_line",
359
+ "chain_hash",
360
+ "prev_hash",
361
+ "outcome",
362
+ "identification",
363
+ "retention_protected",
364
+ "created_at"
365
+ ];
366
+ var TABLE_LOG_ENTRIES = "asai_log_entries";
367
+ var SQLITE_FALLBACK_KEY = "_logStoreUseFileFallback";
368
+ function getLogStoreConfig($asai) {
369
+ const resolved = resolveStoreConfig($asai, "log");
370
+ return {
371
+ type: resolved.type,
372
+ opt: normalizeStoreOpt("log", resolved.type, resolved.opt)
373
+ };
374
+ }
375
+ __name(getLogStoreConfig, "getLogStoreConfig");
376
+ var STORE_TYPE_LABELS = {
377
+ file: "File",
378
+ sqlite: "SQLite",
379
+ mysql: "MySQL"
380
+ };
381
+ function getLogStoreMeta($asai) {
382
+ const cfg = getLogStoreConfig($asai);
383
+ const effective = getEffectiveStoreType($asai);
384
+ const { type: configuredType, opt } = cfg;
385
+ const type = effective === "none" ? configuredType : effective;
386
+ const enabled = isLogStoreEnabled($asai);
387
+ const logger = $asai?.hostconfig?.logger || {};
388
+ const fallback = $asai?.[SQLITE_FALLBACK_KEY];
389
+ const meta = {
390
+ type,
391
+ configuredType,
392
+ enabled,
393
+ label: STORE_TYPE_LABELS[type] || type,
394
+ mode: type === "file" ? "file-folder" : type,
395
+ dualWrite: true,
396
+ folderManaged: type === "file",
397
+ create: opt.create ?? 1,
398
+ fallbackFrom: fallback ? configuredType : void 0,
399
+ fallbackReason: fallback?.reason,
400
+ compliancePaths: {
401
+ server: logger.path?.server,
402
+ client: logger.path?.client,
403
+ access: logger.path?.access,
404
+ intervention: logger.intervention?.path,
405
+ interventionTest: logger.intervention?.testPath,
406
+ interventionArchive: logger.intervention?.archivePath
407
+ }
408
+ };
409
+ if (type === "file") {
410
+ const paths = getFileStorePaths($asai);
411
+ meta.dir = opt.dir;
412
+ meta.ext = opt.ext || ".json";
413
+ meta.indexDir = paths.index;
414
+ meta.layout = "index/{kind}/{ns}/{source}/{log_date}/{id}.json";
415
+ meta.location = String(opt.dir || "");
416
+ } else if (type === "sqlite") {
417
+ meta.database = opt.database;
418
+ meta.location = String(opt.database || "");
419
+ } else if (type === "mysql") {
420
+ meta.host = opt.host;
421
+ meta.database = opt.database;
422
+ meta.location = `${opt.host || "127.0.0.1"}/${opt.database || "asai_logs"}`;
423
+ }
424
+ return meta;
425
+ }
426
+ __name(getLogStoreMeta, "getLogStoreMeta");
427
+ function isLogStoreEnabled($asai) {
428
+ return getEffectiveStoreType($asai) !== "none";
429
+ }
430
+ __name(isLogStoreEnabled, "isLogStoreEnabled");
431
+ function isLogStoreFileBackend($asai) {
432
+ return getEffectiveStoreType($asai) === "file";
433
+ }
434
+ __name(isLogStoreFileBackend, "isLogStoreFileBackend");
435
+ function prefersDiskLogAccess($asai) {
436
+ return isLogStoreFileBackend($asai);
437
+ }
438
+ __name(prefersDiskLogAccess, "prefersDiskLogAccess");
439
+ function markSqliteFallback($asai, reason) {
440
+ if (!$asai[SQLITE_FALLBACK_KEY]) {
441
+ $asai[SQLITE_FALLBACK_KEY] = { at: Date.now(), reason: String(reason?.message || reason || "sqlite unavailable") };
442
+ try {
443
+ ($asai?.$log || console.warn)("LOG", "[store] SQLite unavailable, fallback to file folder storage:", $asai[SQLITE_FALLBACK_KEY].reason);
444
+ } catch {
445
+ }
446
+ }
447
+ }
448
+ __name(markSqliteFallback, "markSqliteFallback");
449
+ function getEffectiveStoreType($asai) {
450
+ const cfg = getLogStoreConfig($asai).type;
451
+ if ($asai?.[SQLITE_FALLBACK_KEY] && (cfg === "sqlite" || cfg === "mysql")) return "file";
452
+ if (cfg === "file" || cfg === "sqlite" || cfg === "mysql") return cfg;
453
+ return "none";
454
+ }
455
+ __name(getEffectiveStoreType, "getEffectiveStoreType");
456
+ function dbType($asai) {
457
+ return getEffectiveStoreType($asai);
458
+ }
459
+ __name(dbType, "dbType");
460
+ function rowToRecord2(row) {
461
+ const out = { ...row };
462
+ for (const k of ["severity", "retention_protected", "created_at", "id"]) {
463
+ if (out[k] != null && out[k] !== "") out[k] = Number(out[k]);
464
+ }
465
+ return out;
466
+ }
467
+ __name(rowToRecord2, "rowToRecord");
468
+ function isTableMissing(err) {
469
+ const msg = String(err?.message || err || "");
470
+ return msg.includes("no such table") || msg.includes("doesn't exist");
471
+ }
472
+ __name(isTableMissing, "isTableMissing");
473
+ function isSqliteUnavailable(err) {
474
+ const msg = String(err?.message || err || "").toLowerCase();
475
+ return isTableMissing(err) || msg.includes("sqlite") || msg.includes("cannot open") || msg.includes("unable to open") || msg.includes("enoent") || msg.includes("not a directory");
476
+ }
477
+ __name(isSqliteUnavailable, "isSqliteUnavailable");
478
+ var LOG_TABLE_ENSURED = "_logTableEnsured";
479
+ var ensureLogTablePromise = null;
480
+ async function ensureLogTable($asai) {
481
+ if ($asai[LOG_TABLE_ENSURED]) return;
482
+ if (getLogStoreConfig($asai).type !== "sqlite") return;
483
+ if (!ensureLogTablePromise) {
484
+ ensureLogTablePromise = (async () => {
485
+ const db = getDb($asai);
486
+ try {
487
+ await db.sqlDb({ type: "select", table: TABLE_LOG_ENTRIES, field: ["id"], limit: 1 });
488
+ } catch (err) {
489
+ if (!isTableMissing(err)) throw err;
490
+ await db.sqlDb({
491
+ type: "insert",
492
+ table: TABLE_LOG_ENTRIES,
493
+ field: [...LOG_ENTRY_FIELDS],
494
+ value: [
495
+ LOG_ENTRY_FIELDS.map((f) => {
496
+ if (f === "severity" || f === "retention_protected" || f === "created_at") return qNum(0);
497
+ return qStr("", "sqlite");
498
+ })
499
+ ]
500
+ });
501
+ }
502
+ $asai[LOG_TABLE_ENSURED] = true;
503
+ })();
504
+ }
505
+ try {
506
+ await ensureLogTablePromise;
507
+ } catch (err) {
508
+ ensureLogTablePromise = null;
509
+ throw err;
510
+ }
511
+ }
512
+ __name(ensureLogTable, "ensureLogTable");
513
+ async function beforeSqliteLogOp($asai) {
514
+ if (getLogStoreConfig($asai).type === "sqlite" && !$asai[SQLITE_FALLBACK_KEY]) {
515
+ await ensureLogTable($asai);
516
+ }
517
+ }
518
+ __name(beforeSqliteLogOp, "beforeSqliteLogOp");
519
+ function isLogStoreSqlite($asai) {
520
+ return getEffectiveStoreType($asai) === "sqlite" || getEffectiveStoreType($asai) === "mysql";
521
+ }
522
+ __name(isLogStoreSqlite, "isLogStoreSqlite");
523
+ function getDb($asai) {
524
+ return getDataServer($asai, "log");
525
+ }
526
+ __name(getDb, "getDb");
527
+ async function dbInsertLogEntry($asai, row) {
528
+ if (!isLogStoreEnabled($asai)) return;
529
+ const type = dbType($asai);
530
+ if (type === "file") {
531
+ await fileStoreInsert($asai, row);
532
+ return;
533
+ }
534
+ const db = getDb($asai);
535
+ try {
536
+ await beforeSqliteLogOp($asai);
537
+ await db.sqlDb({
538
+ type: "insert",
539
+ table: TABLE_LOG_ENTRIES,
540
+ field: [...LOG_ENTRY_FIELDS],
541
+ value: [
542
+ LOG_ENTRY_FIELDS.map((f) => {
543
+ const v = row[f];
544
+ if (f === "severity" || f === "retention_protected" || f === "created_at") return qNum(v);
545
+ return qStr(v == null ? "" : String(v), type);
546
+ })
547
+ ]
548
+ });
549
+ } catch (err) {
550
+ if (getLogStoreConfig($asai).type === "sqlite" && isSqliteUnavailable(err)) {
551
+ markSqliteFallback($asai, err);
552
+ await fileStoreInsert($asai, row);
553
+ return;
554
+ }
555
+ throw err;
556
+ }
557
+ }
558
+ __name(dbInsertLogEntry, "dbInsertLogEntry");
559
+ async function dbQueryLogEntries($asai, filter = {}) {
560
+ if (!isLogStoreEnabled($asai)) return [];
561
+ const type = dbType($asai);
562
+ if (type === "file") {
563
+ return fileStoreQuery($asai, filter);
564
+ }
565
+ const db = getDb($asai);
566
+ const where = [];
567
+ if (filter.kind) where.push(["kind", "=", qStr(filter.kind, type)]);
568
+ if (filter.ns) where.push(["ns", "=", qStr(filter.ns, type)]);
569
+ if (filter.source) where.push(["source", "=", qStr(filter.source, type)]);
570
+ if (filter.log_date) where.push(["log_date", "=", qStr(filter.log_date, type)]);
571
+ if (filter.file_name) where.push(["file_name", "=", qStr(filter.file_name, type)]);
572
+ try {
573
+ await beforeSqliteLogOp($asai);
574
+ const res = await db.sqlDb({
575
+ type: "select",
576
+ table: TABLE_LOG_ENTRIES,
577
+ field: ["id", ...LOG_ENTRY_FIELDS],
578
+ where: where.length ? where : void 0,
579
+ order: [["created_at", "desc"], ["id", "desc"]],
580
+ limit: filter.limit ?? 500
581
+ });
582
+ return asRows(res).map(rowToRecord2);
583
+ } catch (err) {
584
+ if (isTableMissing(err) || isSqliteUnavailable(err)) {
585
+ if (getLogStoreConfig($asai).type === "sqlite") markSqliteFallback($asai, err);
586
+ return fileStoreQuery($asai, filter);
587
+ }
588
+ throw err;
589
+ }
590
+ }
591
+ __name(dbQueryLogEntries, "dbQueryLogEntries");
592
+ async function dbGetLogEntry($asai, id) {
593
+ if (!isLogStoreEnabled($asai)) return null;
594
+ const type = dbType($asai);
595
+ if (type === "file") {
596
+ return fileStoreGet($asai, id);
597
+ }
598
+ const db = getDb($asai);
599
+ try {
600
+ await beforeSqliteLogOp($asai);
601
+ const res = await db.sqlDb({
602
+ type: "select",
603
+ table: TABLE_LOG_ENTRIES,
604
+ field: ["id", ...LOG_ENTRY_FIELDS],
605
+ where: [["id", "=", qNum(Number(id))]],
606
+ limit: 1
607
+ });
608
+ const rows = asRows(res);
609
+ return rows.length ? rowToRecord2(rows[0]) : null;
610
+ } catch (err) {
611
+ if (isTableMissing(err) || isSqliteUnavailable(err)) {
612
+ if (getLogStoreConfig($asai).type === "sqlite") markSqliteFallback($asai, err);
613
+ return fileStoreGet($asai, id);
614
+ }
615
+ throw err;
616
+ }
617
+ }
618
+ __name(dbGetLogEntry, "dbGetLogEntry");
619
+ async function dbListLogGroups($asai, filter = {}) {
620
+ const entries = await dbQueryLogEntries($asai, {
621
+ kind: filter.kind,
622
+ ns: filter.ns,
623
+ source: filter.source,
624
+ limit: 5e3
625
+ });
626
+ const groups = /* @__PURE__ */ new Map();
627
+ for (const e of entries) {
628
+ const kind = String(e.kind || "");
629
+ const ns = String(e.ns || "");
630
+ const source = String(e.source || "");
631
+ const logDate = String(e.log_date || "");
632
+ const fileName = String(e.file_name || (kind === "web" ? `log-${logDate}.txt` : ""));
633
+ const key = `${kind}|${ns}|${source}|${fileName}`;
634
+ const created = Number(e.created_at || 0);
635
+ const g = groups.get(key);
636
+ if (!g) {
637
+ groups.set(key, { key, kind, ns, source, log_date: logDate, file_name: fileName, entryCount: 1, lastAt: created });
638
+ } else {
639
+ g.entryCount += 1;
640
+ if (created > g.lastAt) g.lastAt = created;
641
+ }
642
+ }
643
+ return [...groups.values()].sort((a, b) => b.lastAt - a.lastAt);
644
+ }
645
+ __name(dbListLogGroups, "dbListLogGroups");
646
+ function countStatsFromRows(rows) {
647
+ const stats = { total: rows.length, web: 0, intervention: 0, sec: 0, access: 0, prod: 0, test: 0 };
648
+ for (const r of rows) {
649
+ const k = String(r.kind || "");
650
+ if (k === "web") stats.web += 1;
651
+ else if (k === "intervention") stats.intervention += 1;
652
+ else if (k === "sec") stats.sec += 1;
653
+ else if (k === "access") stats.access += 1;
654
+ const ns = String(r.ns || "");
655
+ if (ns === "prod") stats.prod += 1;
656
+ if (ns === "test") stats.test += 1;
657
+ }
658
+ return stats;
659
+ }
660
+ __name(countStatsFromRows, "countStatsFromRows");
661
+ function applySearchFilters2(rows, filter) {
662
+ let out = rows;
663
+ if (filter.keyword) {
664
+ const kw = filter.keyword.toLowerCase();
665
+ out = out.filter((r) => {
666
+ const hay = [r.message, r.raw_line, r.event_type, r.us, r.identification, r.category].map((v) => String(v || "").toLowerCase()).join(" ");
667
+ return hay.includes(kw);
668
+ });
669
+ }
670
+ if (filter.event_type) {
671
+ const et = filter.event_type.toUpperCase();
672
+ out = out.filter((r) => String(r.event_type || "").toUpperCase() === et);
673
+ }
674
+ if (filter.severity_min != null && !Number.isNaN(Number(filter.severity_min))) {
675
+ const min = Number(filter.severity_min);
676
+ out = out.filter((r) => Number(r.severity || 0) >= min);
677
+ }
678
+ if (filter.date_from) {
679
+ out = out.filter((r) => String(r.log_date || "") >= filter.date_from);
680
+ }
681
+ if (filter.date_to) {
682
+ out = out.filter((r) => String(r.log_date || "") <= filter.date_to);
683
+ }
684
+ if (filter.outcome) {
685
+ const oc = filter.outcome.toLowerCase();
686
+ out = out.filter((r) => String(r.outcome || "").toLowerCase() === oc);
687
+ }
688
+ return out;
689
+ }
690
+ __name(applySearchFilters2, "applySearchFilters");
691
+ async function dbSearchLogEntries($asai, filter = {}) {
692
+ if (!isLogStoreEnabled($asai)) return { entries: [], total: 0, truncated: false };
693
+ if (dbType($asai) === "file") return fileStoreSearch($asai, filter);
694
+ const baseLimit = 2e4;
695
+ const rows = await dbQueryLogEntries($asai, {
696
+ kind: filter.kind,
697
+ ns: filter.ns,
698
+ source: filter.source,
699
+ log_date: filter.log_date,
700
+ file_name: filter.file_name,
701
+ limit: baseLimit
702
+ });
703
+ const filtered = applySearchFilters2(rows, filter);
704
+ const offset = Math.max(0, Number(filter.offset) || 0);
705
+ const limit = Math.min(2e3, Math.max(1, Number(filter.limit) || 200));
706
+ const entries = filtered.slice(offset, offset + limit);
707
+ return {
708
+ entries,
709
+ total: filtered.length,
710
+ truncated: rows.length >= baseLimit
711
+ };
712
+ }
713
+ __name(dbSearchLogEntries, "dbSearchLogEntries");
714
+ async function dbLogStats($asai) {
715
+ if (!isLogStoreEnabled($asai)) {
716
+ return { total: 0, web: 0, intervention: 0, sec: 0, access: 0, prod: 0, test: 0 };
717
+ }
718
+ const type = dbType($asai);
719
+ if (type === "file") {
720
+ const disk = await fileStoreDiskStats($asai);
721
+ const index = await fileStoreStats($asai).catch(() => null);
722
+ if (index && index.total > 0) {
723
+ return { ...disk, sec: index.sec, total: Math.max(disk.total, index.total) };
724
+ }
725
+ return disk;
726
+ }
727
+ const db = getDb($asai);
728
+ try {
729
+ await beforeSqliteLogOp($asai);
730
+ const res = await db.sqlDb({
731
+ type: "select",
732
+ table: TABLE_LOG_ENTRIES,
733
+ field: ["kind", "ns"],
734
+ limit: 1e5
735
+ });
736
+ return countStatsFromRows(asRows(res));
737
+ } catch (err) {
738
+ if (isTableMissing(err) || isSqliteUnavailable(err)) {
739
+ if (getLogStoreConfig($asai).type === "sqlite") markSqliteFallback($asai, err);
740
+ return fileStoreDiskStats($asai);
741
+ }
742
+ throw err;
743
+ }
744
+ }
745
+ __name(dbLogStats, "dbLogStats");
746
+ async function dbDeleteLogEntriesByFile($asai, fileName, ns = "") {
747
+ if (!isLogStoreEnabled($asai)) return 0;
748
+ const type = dbType($asai);
749
+ if (type === "file") {
750
+ return fileStoreDeleteByFile($asai, fileName, ns);
751
+ }
752
+ const db = getDb($asai);
753
+ const where = [["file_name", "=", qStr(fileName, type)]];
754
+ if (ns) where.push(["ns", "=", qStr(ns, type)]);
755
+ try {
756
+ await beforeSqliteLogOp($asai);
757
+ const res = await db.sqlDb({
758
+ type: "delete",
759
+ table: TABLE_LOG_ENTRIES,
760
+ where
761
+ });
762
+ if (res && typeof res === "object" && "changes" in res) return Number(res.changes || 0);
763
+ return 0;
764
+ } catch (err) {
765
+ if (isTableMissing(err) || isSqliteUnavailable(err)) {
766
+ if (getLogStoreConfig($asai).type === "sqlite") markSqliteFallback($asai, err);
767
+ return fileStoreDeleteByFile($asai, fileName, ns);
768
+ }
769
+ throw err;
770
+ }
771
+ }
772
+ __name(dbDeleteLogEntriesByFile, "dbDeleteLogEntriesByFile");
773
+
774
+ // src/sysserver/lib/common/LogStore.ts
775
+ async function mirrorWebLog($asai, opts) {
776
+ if (!isLogStoreEnabled($asai)) return;
777
+ const now = /* @__PURE__ */ new Date();
778
+ const logDate = getNowTime(2, now);
779
+ const kind = opts.source === "sec" ? "sec" : "web";
780
+ await dbInsertLogEntry($asai, {
781
+ kind,
782
+ ns: "",
783
+ source: opts.source,
784
+ log_date: logDate,
785
+ file_name: `log-${logDate}.txt`,
786
+ event_type: "",
787
+ category: kind === "sec" ? "AuditLogEvents" : "",
788
+ severity: kind === "sec" ? 7 : 2,
789
+ us: "",
790
+ message: opts.message || opts.rawLine.slice(0, 2e3),
791
+ raw_line: opts.rawLine,
792
+ chain_hash: "",
793
+ prev_hash: "",
794
+ outcome: "",
795
+ identification: "",
796
+ retention_protected: 0,
797
+ created_at: now.getTime()
798
+ });
799
+ }
800
+ __name(mirrorWebLog, "mirrorWebLog");
801
+ async function mirrorInterventionLog($asai, opts) {
802
+ if (!isLogStoreEnabled($asai)) return;
803
+ const logDate = getNowTime(2);
804
+ const isAudit = opts.fileName.includes("deletion-audit");
805
+ await dbInsertLogEntry($asai, {
806
+ kind: "intervention",
807
+ ns: opts.ns,
808
+ source: "",
809
+ log_date: logDate,
810
+ file_name: opts.fileName,
811
+ event_type: opts.event.type,
812
+ category: opts.category,
813
+ severity: opts.severity,
814
+ us: opts.event.us || "",
815
+ message: opts.event.detail || opts.event.name,
816
+ raw_line: opts.rawLine,
817
+ chain_hash: opts.chainHash,
818
+ prev_hash: opts.prevHash,
819
+ outcome: opts.event.outcome || "Success",
820
+ identification: opts.event.identification || "",
821
+ retention_protected: isAudit ? 1 : 0,
822
+ created_at: Date.now()
823
+ });
824
+ }
825
+ __name(mirrorInterventionLog, "mirrorInterventionLog");
826
+ async function mirrorAccessLog($asai, opts) {
827
+ if (!isLogStoreEnabled($asai)) return;
828
+ const now = /* @__PURE__ */ new Date();
829
+ const logDate = getNowTime(2, now);
830
+ const fileName = opts.format === "clf" ? `access-clf-${logDate}.log` : `access-w3c-${logDate}.log`;
831
+ await dbInsertLogEntry($asai, {
832
+ kind: "access",
833
+ ns: "",
834
+ source: opts.format,
835
+ log_date: logDate,
836
+ file_name: fileName,
837
+ event_type: opts.logType || "HTTP",
838
+ category: "RequestErrors",
839
+ severity: opts.status && opts.status >= 500 ? 4 : 2,
840
+ us: "",
841
+ message: `${opts.method || "-"} ${opts.url || "-"} ${opts.status ?? "-"}`,
842
+ raw_line: opts.rawLine.trim(),
843
+ chain_hash: "",
844
+ prev_hash: "",
845
+ outcome: opts.status && opts.status < 400 ? "Success" : "Failure",
846
+ identification: opts.host || "",
847
+ retention_protected: 0,
848
+ created_at: now.getTime()
849
+ });
850
+ }
851
+ __name(mirrorAccessLog, "mirrorAccessLog");
852
+ async function queryUnifiedLogs($asai, filter) {
853
+ return dbQueryLogEntries($asai, filter);
854
+ }
855
+ __name(queryUnifiedLogs, "queryUnifiedLogs");
856
+ async function searchUnifiedLogs($asai, filter) {
857
+ return dbSearchLogEntries($asai, filter);
858
+ }
859
+ __name(searchUnifiedLogs, "searchUnifiedLogs");
860
+ async function exportLogContent($asai, opts) {
861
+ const format = opts.format || "raw";
862
+ const { readInterventionFile } = await import("./InterventionLog-R6CCPU2B.es.js");
863
+ const ns = opts.ns === "test" ? "test" : "prod";
864
+ if (opts.kind === "intervention" && opts.fileName) {
865
+ const data = await readInterventionFile($asai, opts.fileName, ns);
866
+ if (format === "json") {
867
+ return {
868
+ fileName: opts.fileName,
869
+ format,
870
+ content: JSON.stringify({ fileName: opts.fileName, ns, parsed: data.parsed, chain: data.chain, meta: data.meta }, null, 2),
871
+ mime: "application/json",
872
+ lineCount: data.parsed.length
873
+ };
874
+ }
875
+ return {
876
+ fileName: opts.fileName,
877
+ format: format === "cef" ? "cef" : "raw",
878
+ content: data.raw,
879
+ mime: "text/plain",
880
+ lineCount: data.parsed.length
881
+ };
882
+ }
883
+ const fileName = opts.fileName || "";
884
+ const source = opts.source || "server";
885
+ let content = "";
886
+ if (fileName.startsWith("log-")) {
887
+ content = await readWebLogFromStore($asai, source, fileName);
888
+ } else if (isLogStoreEnabled($asai)) {
889
+ const rows = await dbQueryLogEntries($asai, {
890
+ kind: opts.kind === "intervention" ? "intervention" : opts.kind,
891
+ ns: opts.ns,
892
+ source,
893
+ file_name: fileName || void 0,
894
+ limit: 5e3
895
+ });
896
+ content = rows.reverse().map((r) => String(r.raw_line || "")).join("");
897
+ }
898
+ if (format === "json") {
899
+ const rows = await dbQueryLogEntries($asai, {
900
+ kind: opts.kind === "intervention" ? "intervention" : opts.kind,
901
+ ns: opts.ns,
902
+ source,
903
+ file_name: fileName || void 0,
904
+ limit: 5e3
905
+ });
906
+ return {
907
+ fileName: fileName || "export.json",
908
+ format,
909
+ content: JSON.stringify({ fileName, source, entries: rows }, null, 2),
910
+ mime: "application/json",
911
+ lineCount: rows.length
912
+ };
913
+ }
914
+ const lineCount = content ? content.split("\n").filter((l) => l.trim()).length : 0;
915
+ return {
916
+ fileName: fileName || "export.log",
917
+ format: "raw",
918
+ content,
919
+ mime: "text/plain",
920
+ lineCount
921
+ };
922
+ }
923
+ __name(exportLogContent, "exportLogContent");
924
+ async function getComplianceReport($asai, ns = "prod") {
925
+ const { listInterventionFiles, readInterventionFile } = await import("./InterventionLog-R6CCPU2B.es.js");
926
+ const retentionYears = $asai?.hostconfig?.logger?.intervention?.retentionYears ?? 5;
927
+ const stats = await dbLogStats($asai);
928
+ const storeMeta = getLogStoreMeta($asai);
929
+ const effectiveType = getEffectiveStoreType($asai);
930
+ let files = [];
931
+ try {
932
+ files = await listInterventionFiles($asai, ns);
933
+ } catch {
934
+ files = [];
935
+ }
936
+ const chainChecks = [];
937
+ for (const f of files.slice(0, 30)) {
938
+ if (!f.name?.includes(".cef.")) continue;
939
+ try {
940
+ const data = await readInterventionFile($asai, f.name, ns);
941
+ chainChecks.push({
942
+ fileName: f.name,
943
+ entryCount: data.parsed.length,
944
+ chainOk: data.chain.ok,
945
+ brokenLines: data.chain.results.filter((r) => !r.ok).length,
946
+ protectedAudit: !!f.protectedAudit,
947
+ expired: !!f.expired
948
+ });
949
+ } catch {
950
+ chainChecks.push({
951
+ fileName: f.name,
952
+ entryCount: 0,
953
+ chainOk: false,
954
+ brokenLines: -1,
955
+ protectedAudit: !!f.protectedAudit,
956
+ expired: !!f.expired
957
+ });
958
+ }
959
+ }
960
+ const allChainsOk = chainChecks.length > 0 && chainChecks.every((c) => c.chainOk);
961
+ const disk = await measureLogDiskUsage($asai);
962
+ const diskThreshold = Number($asai?.hostconfig?.logger?.diskAlertMb || 512) * 1048576;
963
+ if (disk.totalBytes >= diskThreshold) {
964
+ const { alertDiskUsage } = await import("./log-alert-GLCULMQP.es.js");
965
+ alertDiskUsage($asai, "log", disk.totalBytes, diskThreshold);
966
+ }
967
+ return {
968
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
969
+ ns,
970
+ retentionYears,
971
+ store: {
972
+ enabled: !!storeMeta.enabled,
973
+ type: effectiveType,
974
+ label: storeMeta.label,
975
+ mode: storeMeta.mode,
976
+ location: storeMeta.location,
977
+ dir: storeMeta.dir,
978
+ database: storeMeta.database,
979
+ indexDir: storeMeta.indexDir,
980
+ layout: storeMeta.layout,
981
+ dualWrite: storeMeta.dualWrite,
982
+ folderManaged: storeMeta.folderManaged,
983
+ fallbackFrom: storeMeta.fallbackFrom,
984
+ fallbackReason: storeMeta.fallbackReason
985
+ },
986
+ stats,
987
+ fileCount: files.length,
988
+ disk,
989
+ chainSummary: {
990
+ checked: chainChecks.length,
991
+ allOk: allChainsOk,
992
+ brokenFiles: chainChecks.filter((c) => !c.chainOk).map((c) => c.fileName)
993
+ },
994
+ chainChecks,
995
+ formats: ["CLF", "W3C Extended", "CEF"]
996
+ };
997
+ }
998
+ __name(getComplianceReport, "getComplianceReport");
999
+ async function measureLogDiskUsage($asai) {
1000
+ const fsp = await import("fs/promises");
1001
+ const pathMod = await import("path");
1002
+ const storeMeta = getLogStoreMeta($asai);
1003
+ const dirs = {};
1004
+ const paths = [
1005
+ $asai?.hostconfig?.logger?.path?.access,
1006
+ $asai?.hostconfig?.logger?.path?.server,
1007
+ $asai?.hostconfig?.logger?.path?.client,
1008
+ $asai?.hostconfig?.logger?.intervention?.path,
1009
+ $asai?.hostconfig?.logger?.intervention?.testPath,
1010
+ $asai?.hostconfig?.logger?.intervention?.archivePath
1011
+ ].filter(Boolean);
1012
+ if (storeMeta.type === "file" && storeMeta.dir) {
1013
+ paths.push(String(storeMeta.dir));
1014
+ }
1015
+ async function dirSize(dir) {
1016
+ let total = 0;
1017
+ try {
1018
+ const entries = await fsp.readdir(dir, { withFileTypes: true });
1019
+ for (const ent of entries) {
1020
+ const full = pathMod.join(dir, ent.name);
1021
+ if (ent.isDirectory()) total += await dirSize(full);
1022
+ else {
1023
+ const st = await fsp.stat(full);
1024
+ total += st.size;
1025
+ }
1026
+ }
1027
+ } catch {
1028
+ }
1029
+ return total;
1030
+ }
1031
+ __name(dirSize, "dirSize");
1032
+ async function fileSize(filePath) {
1033
+ try {
1034
+ const st = await fsp.stat(filePath);
1035
+ return st.isFile() ? st.size : 0;
1036
+ } catch {
1037
+ return 0;
1038
+ }
1039
+ }
1040
+ __name(fileSize, "fileSize");
1041
+ let totalBytes = 0;
1042
+ for (const d of paths) {
1043
+ const bytes = await dirSize(d);
1044
+ dirs[d] = bytes;
1045
+ totalBytes += bytes;
1046
+ }
1047
+ if (storeMeta.type === "sqlite" && storeMeta.database) {
1048
+ const dbPath = String(storeMeta.database);
1049
+ const bytes = await fileSize(dbPath);
1050
+ dirs[dbPath] = bytes;
1051
+ totalBytes += bytes;
1052
+ }
1053
+ return { totalBytes, dirs };
1054
+ }
1055
+ __name(measureLogDiskUsage, "measureLogDiskUsage");
1056
+ async function archiveInterventionYear($asai, opts) {
1057
+ const fsp = await import("fs/promises");
1058
+ const path2 = await import("path");
1059
+ const zlib = await import("zlib");
1060
+ const { pipeline } = await import("stream/promises");
1061
+ const { createReadStream, createWriteStream } = await import("fs");
1062
+ const ns = opts.ns || "prod";
1063
+ const { listInterventionFiles, readInterventionFile } = await import("./InterventionLog-R6CCPU2B.es.js");
1064
+ const yearStr = String(opts.year);
1065
+ const archiveBase = $asai?.hostconfig?.logger?.intervention?.archivePath || path2.join($asai?.hostconfig?.logger?.intervention?.path || "./webdata/webdb/log/intervention/", "archive/");
1066
+ const archiveDir = path2.join(archiveBase, yearStr);
1067
+ const files = await listInterventionFiles($asai, ns);
1068
+ const targets = files.filter((f) => f.name.includes(`intervention-${yearStr}-`) && f.name.endsWith(".cef.log"));
1069
+ const archived = [];
1070
+ const skipped = [];
1071
+ const errors = [];
1072
+ for (const f of targets) {
1073
+ const gzName = `${f.name}.gz`;
1074
+ const gzPath = path2.join(archiveDir, gzName);
1075
+ try {
1076
+ const content = await readInterventionFile($asai, f.name, ns);
1077
+ if (!content.chain.ok) {
1078
+ errors.push(`${f.name}: chain verification failed`);
1079
+ continue;
1080
+ }
1081
+ if (opts.dryRun) {
1082
+ skipped.push(`${f.name} (dry-run)`);
1083
+ continue;
1084
+ }
1085
+ await fsp.mkdir(archiveDir, { recursive: true });
1086
+ if (await fsp.stat(gzPath).then(() => true).catch(() => false)) {
1087
+ skipped.push(`${f.name}: archive exists`);
1088
+ continue;
1089
+ }
1090
+ const srcPath = path2.join(
1091
+ ns === "test" ? $asai?.hostconfig?.logger?.intervention?.testPath || "./webdata/webdb/log/intervention-test/" : $asai?.hostconfig?.logger?.intervention?.path || "./webdata/webdb/log/intervention/",
1092
+ f.name
1093
+ );
1094
+ await pipeline(
1095
+ createReadStream(srcPath),
1096
+ zlib.createGzip(),
1097
+ createWriteStream(gzPath)
1098
+ );
1099
+ await fsp.unlink(srcPath);
1100
+ await purgeStoreEntriesForFile($asai, f.name, ns);
1101
+ const { logProcessGuardEvent } = await import("./intervention-hooks-FI4EHOL5.es.js");
1102
+ await logProcessGuardEvent($asai, {
1103
+ action: "archive_intervention",
1104
+ detail: `${f.name} -> ${gzPath}`,
1105
+ outcome: "Success",
1106
+ severity: 6
1107
+ });
1108
+ archived.push(f.name);
1109
+ } catch (err) {
1110
+ errors.push(`${f.name}: ${err?.message || err}`);
1111
+ }
1112
+ }
1113
+ return { archived, skipped, errors };
1114
+ }
1115
+ __name(archiveInterventionYear, "archiveInterventionYear");
1116
+ async function listUnifiedGroups($asai, filter = {}) {
1117
+ return dbListLogGroups($asai, filter);
1118
+ }
1119
+ __name(listUnifiedGroups, "listUnifiedGroups");
1120
+ async function getUnifiedStats($asai) {
1121
+ return dbLogStats($asai);
1122
+ }
1123
+ __name(getUnifiedStats, "getUnifiedStats");
1124
+ async function getUnifiedEntry($asai, id) {
1125
+ return dbGetLogEntry($asai, id);
1126
+ }
1127
+ __name(getUnifiedEntry, "getUnifiedEntry");
1128
+ async function purgeStoreEntriesForFile($asai, fileName, ns = "") {
1129
+ return dbDeleteLogEntriesByFile($asai, fileName, ns);
1130
+ }
1131
+ __name(purgeStoreEntriesForFile, "purgeStoreEntriesForFile");
1132
+ async function purgeSqliteEntriesForFile($asai, fileName, ns = "") {
1133
+ return purgeStoreEntriesForFile($asai, fileName, ns);
1134
+ }
1135
+ __name(purgeSqliteEntriesForFile, "purgeSqliteEntriesForFile");
1136
+ function groupsToManageChildren(groups) {
1137
+ return groups.filter((g) => g.kind === "web" || g.kind === "sec").map((g) => ({
1138
+ name: g.file_name,
1139
+ path: g.file_name,
1140
+ size: g.entryCount,
1141
+ entryCount: g.entryCount,
1142
+ source: g.source,
1143
+ fromStore: true
1144
+ }));
1145
+ }
1146
+ __name(groupsToManageChildren, "groupsToManageChildren");
1147
+ function groupsToInterventionFiles(groups, ns) {
1148
+ return groups.filter((g) => g.kind === "intervention" && (!ns || g.ns === ns)).map((g) => ({
1149
+ name: g.file_name,
1150
+ ns: g.ns || ns,
1151
+ size: g.entryCount,
1152
+ mtime: new Date(g.lastAt).toISOString(),
1153
+ entryCount: g.entryCount,
1154
+ ageDays: 0,
1155
+ retentionDays: 0,
1156
+ retentionYears: 5,
1157
+ expired: false,
1158
+ protectedAudit: g.file_name.includes("deletion-audit"),
1159
+ fromStore: true
1160
+ }));
1161
+ }
1162
+ __name(groupsToInterventionFiles, "groupsToInterventionFiles");
1163
+ async function readWebLogFromStore($asai, source, fileName) {
1164
+ const m = fileName.match(/log-(\d{4}-\d{2}-\d{2})/);
1165
+ const logDate = m?.[1] || "";
1166
+ const rows = await dbQueryLogEntries($asai, {
1167
+ kind: source === "sec" ? "sec" : "web",
1168
+ source,
1169
+ log_date: logDate,
1170
+ limit: 5e3
1171
+ });
1172
+ return rows.reverse().map((r) => String(r.raw_line || "")).join("");
1173
+ }
1174
+ __name(readWebLogFromStore, "readWebLogFromStore");
1175
+
1176
+ export {
1177
+ getLogStoreConfig,
1178
+ getLogStoreMeta,
1179
+ isLogStoreEnabled,
1180
+ isLogStoreFileBackend,
1181
+ prefersDiskLogAccess,
1182
+ getEffectiveStoreType,
1183
+ isLogStoreSqlite,
1184
+ mirrorWebLog,
1185
+ mirrorInterventionLog,
1186
+ mirrorAccessLog,
1187
+ queryUnifiedLogs,
1188
+ searchUnifiedLogs,
1189
+ exportLogContent,
1190
+ getComplianceReport,
1191
+ archiveInterventionYear,
1192
+ listUnifiedGroups,
1193
+ getUnifiedStats,
1194
+ getUnifiedEntry,
1195
+ purgeStoreEntriesForFile,
1196
+ purgeSqliteEntriesForFile,
1197
+ groupsToManageChildren,
1198
+ groupsToInterventionFiles,
1199
+ readWebLogFromStore,
1200
+ LogStore_exports
1201
+ };
1202
+ //# sourceMappingURL=chunk-LOMSUPPU.es.js.map