querysub 0.356.0 → 0.357.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/.cursorrules +8 -0
  2. package/bin/movelogs.js +4 -0
  3. package/package.json +12 -6
  4. package/scripts/postinstall.js +23 -0
  5. package/src/-a-archives/archiveCache.ts +10 -12
  6. package/src/-a-archives/archives.ts +29 -0
  7. package/src/-a-archives/archivesBackBlaze.ts +60 -12
  8. package/src/-a-archives/archivesDisk.ts +27 -8
  9. package/src/-a-archives/archivesLimitedCache.ts +21 -0
  10. package/src/-a-archives/archivesMemoryCache.ts +350 -0
  11. package/src/-a-archives/archivesPrivateFileSystem.ts +22 -0
  12. package/src/-g-core-values/NodeCapabilities.ts +3 -0
  13. package/src/0-path-value-core/auditLogs.ts +5 -1
  14. package/src/0-path-value-core/pathValueCore.ts +7 -7
  15. package/src/4-dom/qreact.tsx +1 -0
  16. package/src/4-querysub/Querysub.ts +1 -5
  17. package/src/config.ts +5 -0
  18. package/src/diagnostics/MachineThreadInfo.tsx +235 -0
  19. package/src/diagnostics/NodeViewer.tsx +3 -2
  20. package/src/diagnostics/logs/FastArchiveAppendable.ts +79 -42
  21. package/src/diagnostics/logs/FastArchiveController.ts +102 -63
  22. package/src/diagnostics/logs/FastArchiveViewer.tsx +36 -8
  23. package/src/diagnostics/logs/IndexedLogs/BufferIndex.ts +461 -0
  24. package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.cpp +327 -0
  25. package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.d.ts +18 -0
  26. package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.js +1 -0
  27. package/src/diagnostics/logs/IndexedLogs/BufferIndexHelpers.ts +140 -0
  28. package/src/diagnostics/logs/IndexedLogs/BufferIndexLogsOptimizationConstants.ts +22 -0
  29. package/src/diagnostics/logs/IndexedLogs/BufferIndexWAT.wat +1145 -0
  30. package/src/diagnostics/logs/IndexedLogs/BufferIndexWAT.wat.d.ts +178 -0
  31. package/src/diagnostics/logs/IndexedLogs/BufferListStreamer.ts +206 -0
  32. package/src/diagnostics/logs/IndexedLogs/BufferUnitIndex.ts +719 -0
  33. package/src/diagnostics/logs/IndexedLogs/BufferUnitSet.ts +146 -0
  34. package/src/diagnostics/logs/IndexedLogs/FilePathSelector.tsx +408 -0
  35. package/src/diagnostics/logs/IndexedLogs/FindProgressTracker.ts +45 -0
  36. package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +598 -0
  37. package/src/diagnostics/logs/IndexedLogs/LogStreamer.ts +47 -0
  38. package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +702 -0
  39. package/src/diagnostics/logs/IndexedLogs/TimeFileTree.ts +236 -0
  40. package/src/diagnostics/logs/IndexedLogs/binding.gyp +23 -0
  41. package/src/diagnostics/logs/IndexedLogs/moveIndexLogsToPublic.ts +221 -0
  42. package/src/diagnostics/logs/IndexedLogs/moveLogsEntry.ts +10 -0
  43. package/src/diagnostics/logs/LogViewer2.tsx +120 -55
  44. package/src/diagnostics/logs/TimeRangeSelector.tsx +5 -2
  45. package/src/diagnostics/logs/diskLogger.ts +32 -48
  46. package/src/diagnostics/logs/errorNotifications/ErrorNotificationController.ts +3 -2
  47. package/src/diagnostics/logs/errorNotifications/errorDigests.tsx +1 -0
  48. package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePages.tsx +150 -0
  49. package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +132 -15
  50. package/src/diagnostics/logs/lifeCycleAnalysis/test.ts +180 -0
  51. package/src/diagnostics/logs/lifeCycleAnalysis/test.wat +106 -0
  52. package/src/diagnostics/logs/lifeCycleAnalysis/test.wat.d.ts +2 -0
  53. package/src/diagnostics/logs/lifeCycleAnalysis/testHoist.ts +5 -0
  54. package/src/diagnostics/logs/logViewerExtractField.ts +2 -3
  55. package/src/diagnostics/managementPages.tsx +10 -0
  56. package/src/diagnostics/trackResources.ts +1 -1
  57. package/src/misc/lz4_wasm_nodejs.d.ts +34 -0
  58. package/src/misc/lz4_wasm_nodejs.js +178 -0
  59. package/src/misc/lz4_wasm_nodejs_bg.js +94 -0
  60. package/src/misc/lz4_wasm_nodejs_bg.wasm +0 -0
  61. package/src/misc/lz4_wasm_nodejs_bg.wasm.d.ts +15 -0
  62. package/src/storage/CompressedStream.ts +13 -0
  63. package/src/storage/LZ4.ts +32 -0
  64. package/src/storage/ZSTD.ts +10 -0
  65. package/src/wat/watCompiler.ts +1716 -0
  66. package/src/wat/watGrammar.pegjs +93 -0
  67. package/src/wat/watHandler.ts +179 -0
  68. package/src/wat/watInstructions.txt +707 -0
  69. package/src/zip.ts +3 -89
  70. package/src/diagnostics/logs/lifeCycleAnalysis/spec.md +0 -125
@@ -0,0 +1,236 @@
1
+ import { Archives } from "../../../-a-archives/archives";
2
+ import { getOwnThreadId, getOwnMachineId } from "../../../-f-node-discovery/NodeDiscovery";
3
+
4
+ export type TimeFilePath = {
5
+ fullPath: string;
6
+
7
+ // If not pending, this isn't the source, this is just the writer.
8
+ threadId?: string;
9
+ // Presently machine should always be set. But it might not if we start merging logs in backblaze.
10
+ machineId?: string;
11
+
12
+ // If logCount is undefined it means it's a pending file
13
+ logCount?: number;
14
+ uncompressedSize?: number;
15
+ compressedSize?: number;
16
+
17
+ startTime: number;
18
+ endTime: number;
19
+
20
+ // Probably just random?
21
+ dedupe: number;
22
+ };
23
+
24
+ const LOG_FILE_EXTENSION = ".logfile";
25
+
26
+ function encodeLogFilePath(path: Omit<TimeFilePath, "fullPath">): string {
27
+ // Create folder structure: year/month/day/
28
+ const date = new Date(path.startTime);
29
+ const year = date.getUTCFullYear();
30
+ const month = String(date.getUTCMonth() + 1).padStart(2, "0");
31
+ const day = String(date.getUTCDate()).padStart(2, "0");
32
+
33
+ const folderPath = `${year}/${month}/${day}/`;
34
+
35
+ // Build file name with dashed parts
36
+ const parts: string[] = [];
37
+
38
+ if (path.threadId !== undefined) {
39
+ parts.push("threadid", path.threadId);
40
+ }
41
+ if (path.machineId !== undefined) {
42
+ parts.push("machineid", path.machineId);
43
+ }
44
+ parts.push("start", String(path.startTime));
45
+ parts.push("end", String(path.endTime));
46
+ parts.push("dedupe", String(path.dedupe));
47
+ if (path.logCount !== undefined) {
48
+ parts.push("logcount", String(path.logCount));
49
+ }
50
+ if (path.uncompressedSize !== undefined) {
51
+ parts.push("uncompressed", String(path.uncompressedSize));
52
+ }
53
+ if (path.compressedSize !== undefined) {
54
+ parts.push("compressed", String(path.compressedSize));
55
+ }
56
+
57
+ const fileName = parts.join("-") + LOG_FILE_EXTENSION;
58
+
59
+ return folderPath + fileName;
60
+ }
61
+
62
+ const KEY_MAPPING: Record<string, { field: keyof Omit<TimeFilePath, "fullPath">; parseAsNumber: boolean }> = {
63
+ "threadid": { field: "threadId", parseAsNumber: false },
64
+ "machineid": { field: "machineId", parseAsNumber: false },
65
+ "start": { field: "startTime", parseAsNumber: true },
66
+ "end": { field: "endTime", parseAsNumber: true },
67
+ "dedupe": { field: "dedupe", parseAsNumber: true },
68
+ "logcount": { field: "logCount", parseAsNumber: true },
69
+ "uncompressed": { field: "uncompressedSize", parseAsNumber: true },
70
+ "compressed": { field: "compressedSize", parseAsNumber: true },
71
+ };
72
+
73
+ function decodeLogFilePath(path: string): TimeFilePath | undefined {
74
+ if (!path.endsWith(LOG_FILE_EXTENSION)) {
75
+ return undefined;
76
+ }
77
+
78
+ // Extract the file name from the path
79
+ const lastSlash = path.lastIndexOf("/");
80
+ const fileName = lastSlash >= 0 ? path.substring(lastSlash + 1) : path;
81
+
82
+ // Remove extension
83
+ const nameWithoutExt = fileName.substring(0, fileName.length - LOG_FILE_EXTENSION.length);
84
+
85
+ // Parse the dashed parts
86
+ const parts = nameWithoutExt.split("-");
87
+
88
+ const result: TimeFilePath = {
89
+ fullPath: path,
90
+ startTime: 0,
91
+ endTime: 0,
92
+ dedupe: 0,
93
+ };
94
+
95
+ for (let i = 0; i < parts.length; i++) {
96
+ const key = parts[i];
97
+ const mapping = KEY_MAPPING[key];
98
+
99
+ if (mapping && i + 1 < parts.length) {
100
+ const value = parts[i + 1];
101
+ (result as any)[mapping.field] = mapping.parseAsNumber ? parseInt(value, 10) : value;
102
+ i++;
103
+ }
104
+ }
105
+
106
+ return result;
107
+ }
108
+
109
+ // NOTE: This class will add its own extensions to the files, and it'll use it to detect these files. You can append your own extension and then we will ignore those files.
110
+ export class TimeFileTree {
111
+ public constructor(public archives: Archives) { }
112
+
113
+ public async findAllPaths(config: {
114
+ startTime: number;
115
+ endTime: number;
116
+ }): Promise<TimeFilePath[]> {
117
+ const results: TimeFilePath[] = [];
118
+
119
+ // Generate all year/month/day combinations in the range
120
+ const startDate = new Date(config.startTime);
121
+ const endDate = new Date(config.endTime);
122
+
123
+ const startYear = startDate.getUTCFullYear();
124
+ const endYear = endDate.getUTCFullYear();
125
+
126
+ // Find all years in range
127
+ const years = await this.archives.find("", { shallow: true, type: "folders" });
128
+
129
+ for (const yearFolder of years) {
130
+ // yearFolder is a full path like "2024"
131
+ const year = parseInt(yearFolder.split("/").at(-1) || "", 10);
132
+
133
+ if (isNaN(year) || year < startYear || year > endYear) {
134
+ continue;
135
+ }
136
+
137
+ // Find all months in this year
138
+ const months = await this.archives.find(yearFolder + "/", { shallow: true, type: "folders" });
139
+
140
+ for (const monthFolder of months) {
141
+ // monthFolder is a full path like "2024/01"
142
+ const month = parseInt(monthFolder.split("/").at(-1) || "", 10);
143
+
144
+ if (isNaN(month) || month < 1 || month > 12) {
145
+ continue;
146
+ }
147
+
148
+ // Check if this month is in range
149
+ const monthDate = new Date(Date.UTC(year, month - 1, 1));
150
+ const monthEndDate = new Date(Date.UTC(year, month, 0, 23, 59, 59, 999));
151
+
152
+ if (monthEndDate.getTime() < config.startTime || monthDate.getTime() > config.endTime) {
153
+ continue;
154
+ }
155
+
156
+ // Find all days in this month
157
+ const days = await this.archives.find(monthFolder + "/", { shallow: true, type: "folders" });
158
+
159
+ for (const dayFolder of days) {
160
+ // dayFolder is a full path like "2024/01/15"
161
+ const day = parseInt(dayFolder.split("/").at(-1) || "", 10);
162
+
163
+ if (isNaN(day) || day < 1 || day > 31) {
164
+ continue;
165
+ }
166
+
167
+ // Check if this day is in range
168
+ const dayDate = new Date(Date.UTC(year, month - 1, day, 0, 0, 0, 0));
169
+ const dayEndDate = new Date(Date.UTC(year, month - 1, day, 23, 59, 59, 999));
170
+
171
+ if (dayEndDate.getTime() < config.startTime || dayDate.getTime() > config.endTime) {
172
+ continue;
173
+ }
174
+
175
+ // Find all log files in this day
176
+ const files = await this.archives.find(dayFolder + "/", { shallow: true, type: "files" });
177
+
178
+ for (const file of files) {
179
+ const decoded = decodeLogFilePath(file);
180
+
181
+ if (decoded === undefined) {
182
+ continue;
183
+ }
184
+
185
+ // Check if file's time range overlaps with requested range
186
+ if (decoded.endTime >= config.startTime && decoded.startTime <= config.endTime) {
187
+ results.push(decoded);
188
+ }
189
+ }
190
+ }
191
+ }
192
+ }
193
+
194
+ return results;
195
+ }
196
+
197
+ public async deleteAll() {
198
+ let rootFolders = await this.archives.find("", { shallow: true, type: "folders" });
199
+ for (let rootFolder of rootFolders) {
200
+ await this.archives.del(rootFolder);
201
+ }
202
+ }
203
+
204
+ public getNewPendingPath(config: {
205
+ startTime: number;
206
+ endTime: number;
207
+ }): string {
208
+ return encodeLogFilePath({
209
+ startTime: config.startTime,
210
+ endTime: config.endTime,
211
+ threadId: getOwnThreadId(),
212
+ machineId: getOwnMachineId(),
213
+ dedupe: dedupeSeqNum++,
214
+ });
215
+ }
216
+
217
+ public getNewFinalPath(config: {
218
+ logCount: number;
219
+ uncompressedSize: number;
220
+ compressedSize: number;
221
+ startTime: number;
222
+ endTime: number;
223
+ }): string {
224
+ return encodeLogFilePath({
225
+ startTime: config.startTime,
226
+ endTime: config.endTime,
227
+ machineId: getOwnMachineId(),
228
+ threadId: getOwnThreadId(),
229
+ dedupe: dedupeSeqNum++,
230
+ logCount: config.logCount,
231
+ uncompressedSize: config.uncompressedSize,
232
+ compressedSize: config.compressedSize,
233
+ });
234
+ }
235
+ }
236
+ let dedupeSeqNum = 0;
@@ -0,0 +1,23 @@
1
+ {
2
+ "targets": [
3
+ {
4
+ "target_name": "BufferIndexCPP",
5
+ "sources": [ "BufferIndexCPP.cpp" ],
6
+ "cflags": [ "-O3", "-march=native" ],
7
+ "cflags_cc": [ "-O3", "-march=native" ],
8
+ "msvs_settings": {
9
+ "VCCLCompilerTool": {
10
+ "Optimization": 3,
11
+ "FavorSizeOrSpeed": 1,
12
+ "InlineFunctionExpansion": 2,
13
+ "EnableIntrinsicFunctions": "true",
14
+ "RuntimeLibrary": 0
15
+ }
16
+ },
17
+ "xcode_settings": {
18
+ "GCC_OPTIMIZATION_LEVEL": "3",
19
+ "OTHER_CFLAGS": [ "-march=native" ]
20
+ }
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,221 @@
1
+ import { delay } from "socket-function/src/batching";
2
+ import { sort, keyByArray } from "socket-function/src/misc";
3
+ import { Archives } from "../../../-a-archives/archives";
4
+ import { getOwnThreadId } from "../../../-f-node-discovery/NodeDiscovery";
5
+ import { BufferIndex } from "./BufferIndex";
6
+ import { LogStreamer } from "./LogStreamer";
7
+ import { TimeFileTree } from "./TimeFileTree";
8
+ import { green, magenta } from "socket-function/src/formatting/logColors";
9
+ import { formatNumber, formatTime } from "socket-function/src/formatting/format";
10
+
11
+
12
+
13
+ export async function moveLogsToPublic(config: {
14
+ publicMoveThreshold: number;
15
+ maxSingleFileData: number;
16
+ movingTimeout: number;
17
+ // Unsafe, but useful for testing
18
+ forceAll: boolean;
19
+ localLogs: Archives;
20
+ publicLogs: Archives;
21
+ getIndexPath: (path: string) => string;
22
+ }) {
23
+ let { forceAll, localLogs, publicLogs, publicMoveThreshold, maxSingleFileData, getIndexPath, movingTimeout } = config;
24
+ let now = Date.now();
25
+ let threadId = getOwnThreadId();
26
+ let ourMovingFileName = `${now}-${threadId}.moving`;
27
+
28
+ async function tryToGetMoveLock(): Promise<boolean> {
29
+
30
+ // Helper function to parse moving file names and extract timestamp
31
+ const parseMovingFileName = (fileName: string): number | undefined => {
32
+ if (!fileName.endsWith(".moving")) return undefined;
33
+ let parts = fileName.split("-");
34
+ if (parts.length < 2) return undefined;
35
+ let timestamp = parseInt(parts[0]);
36
+ if (isNaN(timestamp)) return undefined;
37
+ return timestamp;
38
+ };
39
+
40
+ // Helper function to check and clean up stale moving files
41
+ const checkAndCleanMovingFiles = async (): Promise<string[]> => {
42
+ // 1) We do a shallow read of the local logs directory and then find any files that have the moving extension and then we see when they've been written.
43
+ let allFiles = await localLogs.find("", { shallow: true, type: "files" });
44
+ let movingFiles = allFiles.filter(x => x.endsWith(".moving"));
45
+
46
+ let now = Date.now();
47
+ let validMovingFiles: string[] = [];
48
+ let stalePaths: string[] = [];
49
+
50
+ for (let movingFile of movingFiles) {
51
+ let timestamp = parseMovingFileName(movingFile);
52
+ if (timestamp === undefined) continue;
53
+
54
+ let age = now - timestamp;
55
+ // 2) If they're not past our timeout threshold at the top of the file, Then we just return (NOOP).
56
+ // 3) If any are past their timeout threshold, we delete them.
57
+ if (age > movingTimeout) {
58
+ stalePaths.push(movingFile);
59
+ } else {
60
+ validMovingFiles.push(movingFile);
61
+ }
62
+ }
63
+
64
+ // Delete stale moving files
65
+ for (let stalePath of stalePaths) {
66
+ await localLogs.del(stalePath);
67
+ }
68
+
69
+ // Sort by timestamp (oldest first)
70
+ sort(validMovingFiles, x => parseMovingFileName(x) || Infinity);
71
+
72
+ return validMovingFiles;
73
+ };
74
+
75
+
76
+ // Initial check for existing moving files
77
+ let validMovingFiles = await checkAndCleanMovingFiles();
78
+ // 2) If they're not past our timeout threshold at the top of the file, Then we just return (NOOP).
79
+ if (validMovingFiles.length > 0) {
80
+ return false;
81
+ }
82
+
83
+ // 4) We then write our own moving file flag
84
+ await localLogs.set(ourMovingFileName, Buffer.from("moving"));
85
+
86
+ if (!forceAll) {
87
+ // 5) Wait 15 seconds, to let things settle, so we aren't racing
88
+ await delay(15000);
89
+ }
90
+
91
+ // 6) Check again if anything is moving and it's past the threshold (This code should be in a function that's local to this function, so we can easily run it again)
92
+ validMovingFiles = await checkAndCleanMovingFiles();
93
+
94
+ // 7) Also, out of all of the moving files which aren't beyond the timeout, we need to make sure ours is the oldest, but not older than half the timeout. If this isn't true, then we just return.
95
+ let oldestMovingFile = validMovingFiles[0];
96
+ if (oldestMovingFile !== ourMovingFileName) {
97
+ // Clean up our moving file since we didn't get the lock
98
+ await localLogs.del(ourMovingFileName);
99
+ return false;
100
+ }
101
+
102
+ let ourTimestamp = parseMovingFileName(ourMovingFileName);
103
+ if (ourTimestamp !== undefined) {
104
+ let ourAge = Date.now() - ourTimestamp;
105
+ // If we got even close to the threshold, we need to abort. Because if we're close to the threshold, someone else might have thought we exceeded the threshold, and starting moving themselves.
106
+ if (ourAge > movingTimeout / 2) {
107
+ // Clean up our moving file since it's too old
108
+ await localLogs.del(ourMovingFileName);
109
+ return false;
110
+ }
111
+ }
112
+
113
+ // 8) Then, if all this passes, return true
114
+ return true;
115
+ }
116
+
117
+ let localPaths = await new TimeFileTree(localLogs).findAllPaths({
118
+ startTime: 0,
119
+ endTime: Date.now(),
120
+ });
121
+
122
+ if (!forceAll) {
123
+ let threshold = Date.now() - publicMoveThreshold;
124
+ localPaths = localPaths.filter(x => x.startTime < threshold);
125
+ }
126
+
127
+ if (!localPaths.length) return;
128
+
129
+ if (!await tryToGetMoveLock()) return;
130
+
131
+ let byStartTime = keyByArray(localPaths, x => x.startTime);
132
+
133
+ for (let group of byStartTime.values()) {
134
+ let time = Date.now();
135
+ let buffers: Buffer[] = [];
136
+ await Promise.all(group.map(async x => {
137
+ let buffer = await localLogs.get(x.fullPath);
138
+ if (buffer) {
139
+ buffers.push(buffer);
140
+ }
141
+ }));
142
+ if (buffers.length === 0) continue;
143
+
144
+ console.log(magenta(`Merging and moving ${group.length} log files backblaze`));
145
+
146
+ let allBuffers: Buffer[][] = [];
147
+
148
+ for (let buffer of buffers) {
149
+ let decoded = await BufferIndex.decodeAll(buffer);
150
+ allBuffers.push(decoded);
151
+ }
152
+
153
+ let buffersFlat = allBuffers.flat();
154
+ // Reverse them, so the newest come first.
155
+ buffersFlat.reverse();
156
+ // Group buffersFlat so we are under MAX_SINGLE_FILE_DATA
157
+ let groupedBuffers: Buffer[][] = [];
158
+ let currentGroup: Buffer[] = [];
159
+ let currentGroupSize = maxSingleFileData + 1;
160
+ for (let buffer of buffersFlat) {
161
+ if (currentGroupSize > maxSingleFileData) {
162
+ currentGroup = [];
163
+ groupedBuffers.push(currentGroup);
164
+ currentGroupSize = 0;
165
+ }
166
+ currentGroup.push(buffer);
167
+ currentGroupSize += buffer.length;
168
+ }
169
+
170
+ let startTime = Math.min(...group.map(x => x.startTime));
171
+ let endTime = Math.max(...group.map(x => x.endTime));
172
+
173
+ let encoded: {
174
+ data: Buffer;
175
+ index: Buffer;
176
+ compressedSize: number;
177
+ uncompressedSize: number;
178
+ logCount: number;
179
+ }[] = [];
180
+ for (let group of groupedBuffers) {
181
+ let uncompressedSize = 0;
182
+ for (let buffer of group) {
183
+ uncompressedSize += buffer.length;
184
+ }
185
+ let obj = BufferIndex.encodeAll({
186
+ data: group,
187
+ });
188
+ encoded.push({
189
+ data: obj.data,
190
+ index: obj.index,
191
+ compressedSize: obj.data.length,
192
+ uncompressedSize,
193
+ logCount: group.length,
194
+ });
195
+ // Wait, so if we have to encode a lot of data, we don't block for too long?
196
+ await delay(0);
197
+ }
198
+
199
+ let backblazeManager = new TimeFileTree(publicLogs);
200
+ for (let obj of encoded) {
201
+ let path = backblazeManager.getNewFinalPath({
202
+ logCount: obj.logCount,
203
+ uncompressedSize: obj.uncompressedSize,
204
+ compressedSize: obj.compressedSize,
205
+ startTime,
206
+ endTime,
207
+ });
208
+ let indexPath = getIndexPath(path);
209
+ await publicLogs.set(indexPath, obj.index);
210
+ await publicLogs.set(path, obj.data);
211
+ }
212
+
213
+ console.log(green(`Wrote ${encoded.length} log files to backblaze (${formatNumber(encoded.reduce((acc, x) => acc + x.uncompressedSize, 0))}B compressed to ${formatNumber(encoded.reduce((acc, x) => acc + x.compressedSize, 0))}B + ${formatNumber(encoded.reduce((acc, x) => acc + x.index.length, 0))}B index) in ${formatTime(Date.now() - time)}`));
214
+
215
+ for (let path of group) {
216
+ await localLogs.del(path.fullPath);
217
+ }
218
+ }
219
+
220
+ await localLogs.del(ourMovingFileName);
221
+ }
@@ -0,0 +1,10 @@
1
+ import "../../../inject";
2
+
3
+ import { logErrors } from "../../../errors";
4
+ import { IndexedLogs } from "./IndexedLogs";
5
+
6
+ async function main() {
7
+ IndexedLogs.runLogMoveLoop();
8
+ }
9
+
10
+ main().catch(logErrors);