log-search 1.0.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.
- package/LICENSE +21 -0
- package/README.md +226 -0
- package/bin/log-search.js +45 -0
- package/dist/cli/commands/clear.d.ts +9 -0
- package/dist/cli/commands/clear.d.ts.map +1 -0
- package/dist/cli/commands/clear.js +116 -0
- package/dist/cli/commands/clear.js.map +1 -0
- package/dist/cli/commands/index.d.ts +8 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +118 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/info.d.ts +8 -0
- package/dist/cli/commands/info.d.ts.map +1 -0
- package/dist/cli/commands/info.js +96 -0
- package/dist/cli/commands/info.js.map +1 -0
- package/dist/cli/commands/search.d.ts +9 -0
- package/dist/cli/commands/search.d.ts.map +1 -0
- package/dist/cli/commands/search.js +178 -0
- package/dist/cli/commands/search.js.map +1 -0
- package/dist/cli/commands/watch.d.ts +8 -0
- package/dist/cli/commands/watch.d.ts.map +1 -0
- package/dist/cli/commands/watch.js +141 -0
- package/dist/cli/commands/watch.js.map +1 -0
- package/dist/cli/main.d.ts +6 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +57 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output/colorizer.d.ts +36 -0
- package/dist/cli/output/colorizer.d.ts.map +1 -0
- package/dist/cli/output/colorizer.js +101 -0
- package/dist/cli/output/colorizer.js.map +1 -0
- package/dist/cli/output/formatter.d.ts +31 -0
- package/dist/cli/output/formatter.d.ts.map +1 -0
- package/dist/cli/output/formatter.js +146 -0
- package/dist/cli/output/formatter.js.map +1 -0
- package/dist/cli/output/table.d.ts +12 -0
- package/dist/cli/output/table.d.ts.map +1 -0
- package/dist/cli/output/table.js +48 -0
- package/dist/cli/output/table.js.map +1 -0
- package/dist/core/indexer/ChunkProcessor.d.ts +21 -0
- package/dist/core/indexer/ChunkProcessor.d.ts.map +1 -0
- package/dist/core/indexer/ChunkProcessor.js +105 -0
- package/dist/core/indexer/ChunkProcessor.js.map +1 -0
- package/dist/core/indexer/IndexBuilder.d.ts +47 -0
- package/dist/core/indexer/IndexBuilder.d.ts.map +1 -0
- package/dist/core/indexer/IndexBuilder.js +274 -0
- package/dist/core/indexer/IndexBuilder.js.map +1 -0
- package/dist/core/indexer/IndexSerializer.d.ts +30 -0
- package/dist/core/indexer/IndexSerializer.d.ts.map +1 -0
- package/dist/core/indexer/IndexSerializer.js +142 -0
- package/dist/core/indexer/IndexSerializer.js.map +1 -0
- package/dist/core/indexer/OffsetMapper.d.ts +55 -0
- package/dist/core/indexer/OffsetMapper.d.ts.map +1 -0
- package/dist/core/indexer/OffsetMapper.js +94 -0
- package/dist/core/indexer/OffsetMapper.js.map +1 -0
- package/dist/core/indexer/TokenExtractor.d.ts +27 -0
- package/dist/core/indexer/TokenExtractor.d.ts.map +1 -0
- package/dist/core/indexer/TokenExtractor.js +92 -0
- package/dist/core/indexer/TokenExtractor.js.map +1 -0
- package/dist/core/searcher/IndexSearcher.d.ts +37 -0
- package/dist/core/searcher/IndexSearcher.d.ts.map +1 -0
- package/dist/core/searcher/IndexSearcher.js +360 -0
- package/dist/core/searcher/IndexSearcher.js.map +1 -0
- package/dist/core/searcher/RankEngine.d.ts +29 -0
- package/dist/core/searcher/RankEngine.d.ts.map +1 -0
- package/dist/core/searcher/RankEngine.js +90 -0
- package/dist/core/searcher/RankEngine.js.map +1 -0
- package/dist/core/searcher/ResultFetcher.d.ts +37 -0
- package/dist/core/searcher/ResultFetcher.d.ts.map +1 -0
- package/dist/core/searcher/ResultFetcher.js +118 -0
- package/dist/core/searcher/ResultFetcher.js.map +1 -0
- package/dist/core/streaming/ChunkSplitter.d.ts +25 -0
- package/dist/core/streaming/ChunkSplitter.d.ts.map +1 -0
- package/dist/core/streaming/ChunkSplitter.js +71 -0
- package/dist/core/streaming/ChunkSplitter.js.map +1 -0
- package/dist/core/streaming/FileStreamer.d.ts +39 -0
- package/dist/core/streaming/FileStreamer.d.ts.map +1 -0
- package/dist/core/streaming/FileStreamer.js +138 -0
- package/dist/core/streaming/FileStreamer.js.map +1 -0
- package/dist/core/streaming/LineBuffer.d.ts +26 -0
- package/dist/core/streaming/LineBuffer.d.ts.map +1 -0
- package/dist/core/streaming/LineBuffer.js +52 -0
- package/dist/core/streaming/LineBuffer.js.map +1 -0
- package/dist/core/workers/IndexWorker.d.ts +8 -0
- package/dist/core/workers/IndexWorker.d.ts.map +1 -0
- package/dist/core/workers/IndexWorker.js +41 -0
- package/dist/core/workers/IndexWorker.js.map +1 -0
- package/dist/core/workers/SearchWorker.d.ts +7 -0
- package/dist/core/workers/SearchWorker.d.ts.map +1 -0
- package/dist/core/workers/SearchWorker.js +63 -0
- package/dist/core/workers/SearchWorker.js.map +1 -0
- package/dist/core/workers/WorkerPool.d.ts +30 -0
- package/dist/core/workers/WorkerPool.d.ts.map +1 -0
- package/dist/core/workers/WorkerPool.js +132 -0
- package/dist/core/workers/WorkerPool.js.map +1 -0
- package/dist/formats/LogFormatDetector.d.ts +22 -0
- package/dist/formats/LogFormatDetector.d.ts.map +1 -0
- package/dist/formats/LogFormatDetector.js +123 -0
- package/dist/formats/LogFormatDetector.js.map +1 -0
- package/dist/formats/parsers/ApacheParser.d.ts +10 -0
- package/dist/formats/parsers/ApacheParser.d.ts.map +1 -0
- package/dist/formats/parsers/ApacheParser.js +54 -0
- package/dist/formats/parsers/ApacheParser.js.map +1 -0
- package/dist/formats/parsers/GenericParser.d.ts +11 -0
- package/dist/formats/parsers/GenericParser.d.ts.map +1 -0
- package/dist/formats/parsers/GenericParser.js +61 -0
- package/dist/formats/parsers/GenericParser.js.map +1 -0
- package/dist/formats/parsers/JsonParser.d.ts +12 -0
- package/dist/formats/parsers/JsonParser.d.ts.map +1 -0
- package/dist/formats/parsers/JsonParser.js +92 -0
- package/dist/formats/parsers/JsonParser.js.map +1 -0
- package/dist/formats/parsers/NginxParser.d.ts +15 -0
- package/dist/formats/parsers/NginxParser.d.ts.map +1 -0
- package/dist/formats/parsers/NginxParser.js +78 -0
- package/dist/formats/parsers/NginxParser.js.map +1 -0
- package/dist/formats/parsers/SyslogParser.d.ts +10 -0
- package/dist/formats/parsers/SyslogParser.d.ts.map +1 -0
- package/dist/formats/parsers/SyslogParser.js +73 -0
- package/dist/formats/parsers/SyslogParser.js.map +1 -0
- package/dist/formats/schemas/LogSchema.d.ts +70 -0
- package/dist/formats/schemas/LogSchema.d.ts.map +1 -0
- package/dist/formats/schemas/LogSchema.js +7 -0
- package/dist/formats/schemas/LogSchema.js.map +1 -0
- package/dist/index-store/CacheManager.d.ts +45 -0
- package/dist/index-store/CacheManager.d.ts.map +1 -0
- package/dist/index-store/CacheManager.js +84 -0
- package/dist/index-store/CacheManager.js.map +1 -0
- package/dist/index-store/FileWatcher.d.ts +39 -0
- package/dist/index-store/FileWatcher.d.ts.map +1 -0
- package/dist/index-store/FileWatcher.js +121 -0
- package/dist/index-store/FileWatcher.js.map +1 -0
- package/dist/index-store/IncrementalUpdater.d.ts +19 -0
- package/dist/index-store/IncrementalUpdater.d.ts.map +1 -0
- package/dist/index-store/IncrementalUpdater.js +62 -0
- package/dist/index-store/IncrementalUpdater.js.map +1 -0
- package/dist/index-store/IndexStore.d.ts +66 -0
- package/dist/index-store/IndexStore.d.ts.map +1 -0
- package/dist/index-store/IndexStore.js +183 -0
- package/dist/index-store/IndexStore.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +99 -0
- package/dist/index.js.map +1 -0
- package/dist/pro/alerts/AlertEngine.d.ts +35 -0
- package/dist/pro/alerts/AlertEngine.d.ts.map +1 -0
- package/dist/pro/alerts/AlertEngine.js +162 -0
- package/dist/pro/alerts/AlertEngine.js.map +1 -0
- package/dist/pro/alerts/Notifier.d.ts +23 -0
- package/dist/pro/alerts/Notifier.d.ts.map +1 -0
- package/dist/pro/alerts/Notifier.js +173 -0
- package/dist/pro/alerts/Notifier.js.map +1 -0
- package/dist/pro/alerts/RuleParser.d.ts +32 -0
- package/dist/pro/alerts/RuleParser.d.ts.map +1 -0
- package/dist/pro/alerts/RuleParser.js +86 -0
- package/dist/pro/alerts/RuleParser.js.map +1 -0
- package/dist/pro/auth/LicenseValidator.d.ts +29 -0
- package/dist/pro/auth/LicenseValidator.d.ts.map +1 -0
- package/dist/pro/auth/LicenseValidator.js +122 -0
- package/dist/pro/auth/LicenseValidator.js.map +1 -0
- package/dist/pro/auth/TokenManager.d.ts +27 -0
- package/dist/pro/auth/TokenManager.d.ts.map +1 -0
- package/dist/pro/auth/TokenManager.js +98 -0
- package/dist/pro/auth/TokenManager.js.map +1 -0
- package/dist/pro/webui/UIServer.d.ts +34 -0
- package/dist/pro/webui/UIServer.d.ts.map +1 -0
- package/dist/pro/webui/UIServer.js +353 -0
- package/dist/pro/webui/UIServer.js.map +1 -0
- package/dist/query/QueryEngine.d.ts +34 -0
- package/dist/query/QueryEngine.d.ts.map +1 -0
- package/dist/query/QueryEngine.js +187 -0
- package/dist/query/QueryEngine.js.map +1 -0
- package/dist/query/operators/AndOperator.d.ts +18 -0
- package/dist/query/operators/AndOperator.d.ts.map +1 -0
- package/dist/query/operators/AndOperator.js +55 -0
- package/dist/query/operators/AndOperator.js.map +1 -0
- package/dist/query/operators/NotOperator.d.ts +19 -0
- package/dist/query/operators/NotOperator.d.ts.map +1 -0
- package/dist/query/operators/NotOperator.js +43 -0
- package/dist/query/operators/NotOperator.js.map +1 -0
- package/dist/query/operators/OrOperator.d.ts +17 -0
- package/dist/query/operators/OrOperator.d.ts.map +1 -0
- package/dist/query/operators/OrOperator.js +54 -0
- package/dist/query/operators/OrOperator.js.map +1 -0
- package/dist/query/operators/RangeOperator.d.ts +23 -0
- package/dist/query/operators/RangeOperator.d.ts.map +1 -0
- package/dist/query/operators/RangeOperator.js +63 -0
- package/dist/query/operators/RangeOperator.js.map +1 -0
- package/dist/query/regex/FuzzyMatcher.d.ts +29 -0
- package/dist/query/regex/FuzzyMatcher.d.ts.map +1 -0
- package/dist/query/regex/FuzzyMatcher.js +89 -0
- package/dist/query/regex/FuzzyMatcher.js.map +1 -0
- package/dist/query/regex/RegexMatcher.d.ts +31 -0
- package/dist/query/regex/RegexMatcher.d.ts.map +1 -0
- package/dist/query/regex/RegexMatcher.js +73 -0
- package/dist/query/regex/RegexMatcher.js.map +1 -0
- package/dist/types/ConfigTypes.d.ts +78 -0
- package/dist/types/ConfigTypes.d.ts.map +1 -0
- package/dist/types/ConfigTypes.js +7 -0
- package/dist/types/ConfigTypes.js.map +1 -0
- package/dist/types/IndexTypes.d.ts +86 -0
- package/dist/types/IndexTypes.d.ts.map +1 -0
- package/dist/types/IndexTypes.js +7 -0
- package/dist/types/IndexTypes.js.map +1 -0
- package/dist/types/SearchTypes.d.ts +102 -0
- package/dist/types/SearchTypes.d.ts.map +1 -0
- package/dist/types/SearchTypes.js +7 -0
- package/dist/types/SearchTypes.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +24 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/fs-helpers.d.ts +9 -0
- package/dist/utils/fs-helpers.d.ts.map +1 -0
- package/dist/utils/fs-helpers.js +76 -0
- package/dist/utils/fs-helpers.js.map +1 -0
- package/dist/utils/hash.d.ts +7 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +49 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/logger.d.ts +19 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +41 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/performance.d.ts +14 -0
- package/dist/utils/performance.d.ts.map +1 -0
- package/dist/utils/performance.js +32 -0
- package/dist/utils/performance.js.map +1 -0
- package/dist/utils/progress.d.ts +7 -0
- package/dist/utils/progress.d.ts.map +1 -0
- package/dist/utils/progress.js +22 -0
- package/dist/utils/progress.js.map +1 -0
- package/package.json +105 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LicenseValidator.ts
|
|
4
|
+
* Validates Pro license keys.
|
|
5
|
+
* License format: LSEARCH-XXXX-XXXX-XXXX-XXXX (base-32 encoded payload)
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.LicenseValidator = void 0;
|
|
42
|
+
const crypto = __importStar(require("crypto"));
|
|
43
|
+
const os = __importStar(require("os"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const promises_1 = require("fs/promises");
|
|
46
|
+
const LICENSE_RE = /^LSEARCH-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/;
|
|
47
|
+
const PRO_CONFIG_PATH = path.join(os.homedir(), '.log-search', 'pro.json');
|
|
48
|
+
// All Pro features
|
|
49
|
+
const ALL_FEATURES = ['web-ui', 'alerts', 'multi-file', 'api-server', 'reports', 'team-sharing'];
|
|
50
|
+
class LicenseValidator {
|
|
51
|
+
/**
|
|
52
|
+
* Validate a license key format and save it locally.
|
|
53
|
+
*/
|
|
54
|
+
async activate(licenseKey) {
|
|
55
|
+
if (!LICENSE_RE.test(licenseKey.toUpperCase())) {
|
|
56
|
+
throw new Error(`Invalid license key format. Expected: LSEARCH-XXXX-XXXX-XXXX-XXXX`);
|
|
57
|
+
}
|
|
58
|
+
const config = {
|
|
59
|
+
licenseKey: licenseKey.toUpperCase(),
|
|
60
|
+
activationToken: this.generateActivationToken(licenseKey),
|
|
61
|
+
expiresAt: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(),
|
|
62
|
+
features: ALL_FEATURES,
|
|
63
|
+
};
|
|
64
|
+
await this.saveConfig(config);
|
|
65
|
+
return config;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Load and verify stored Pro config.
|
|
69
|
+
* Returns null if not activated or expired.
|
|
70
|
+
*/
|
|
71
|
+
async verify() {
|
|
72
|
+
try {
|
|
73
|
+
const config = await this.loadConfig();
|
|
74
|
+
if (!config)
|
|
75
|
+
return null;
|
|
76
|
+
if (config.expiresAt && new Date(config.expiresAt) < new Date()) {
|
|
77
|
+
return null; // Expired
|
|
78
|
+
}
|
|
79
|
+
return config;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if a specific Pro feature is available.
|
|
87
|
+
*/
|
|
88
|
+
async hasFeature(feature) {
|
|
89
|
+
const config = await this.verify();
|
|
90
|
+
if (!config)
|
|
91
|
+
return false;
|
|
92
|
+
return config.features.includes(feature);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Deactivate Pro license.
|
|
96
|
+
*/
|
|
97
|
+
async deactivate() {
|
|
98
|
+
await this.saveConfig(null);
|
|
99
|
+
}
|
|
100
|
+
generateActivationToken(key) {
|
|
101
|
+
return crypto
|
|
102
|
+
.createHash('sha256')
|
|
103
|
+
.update(key + os.hostname() + os.platform())
|
|
104
|
+
.digest('hex')
|
|
105
|
+
.slice(0, 32);
|
|
106
|
+
}
|
|
107
|
+
async loadConfig() {
|
|
108
|
+
try {
|
|
109
|
+
const raw = await (0, promises_1.readFile)(PRO_CONFIG_PATH, 'utf8');
|
|
110
|
+
return JSON.parse(raw);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async saveConfig(config) {
|
|
117
|
+
await (0, promises_1.mkdir)(path.dirname(PRO_CONFIG_PATH), { recursive: true });
|
|
118
|
+
await (0, promises_1.writeFile)(PRO_CONFIG_PATH, config ? JSON.stringify(config, null, 2) : '{}', 'utf8');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.LicenseValidator = LicenseValidator;
|
|
122
|
+
//# sourceMappingURL=LicenseValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LicenseValidator.js","sourceRoot":"","sources":["../../../src/pro/auth/LicenseValidator.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,+CAAiC;AACjC,uCAAyB;AACzB,2CAA6B;AAC7B,0CAAyD;AAGzD,MAAM,UAAU,GAAG,2DAA2D,CAAC;AAC/E,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;AAE3E,mBAAmB;AACnB,MAAM,YAAY,GAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;AAE/G,MAAa,gBAAgB;IAC3B;;OAEG;IACH,KAAK,CAAC,QAAQ,CAAC,UAAkB;QAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACvF,CAAC;QAED,MAAM,MAAM,GAAc;YACxB,UAAU,EAAE,UAAU,CAAC,WAAW,EAAE;YACpC,eAAe,EAAE,IAAI,CAAC,uBAAuB,CAAC,UAAU,CAAC;YACzD,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;YACzE,QAAQ,EAAE,YAAY;SACvB,CAAC;QAEF,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC9B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM;QACV,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YACvC,IAAI,CAAC,MAAM;gBAAE,OAAO,IAAI,CAAC;YAEzB,IAAI,MAAM,CAAC,SAAS,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC;gBAChE,OAAO,IAAI,CAAC,CAAC,UAAU;YACzB,CAAC;YAED,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,OAAmB;QAClC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACnC,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC1B,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAEO,uBAAuB,CAAC,GAAW;QACzC,OAAO,MAAM;aACV,UAAU,CAAC,QAAQ,CAAC;aACpB,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;aAC3C,MAAM,CAAC,KAAK,CAAC;aACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClB,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAA,mBAAQ,EAAC,eAAe,EAAE,MAAM,CAAC,CAAC;YACpD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,MAAwB;QAC/C,MAAM,IAAA,gBAAK,EAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,IAAA,oBAAS,EACb,eAAe,EACf,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAC/C,MAAM,CACP,CAAC;IACJ,CAAC;CACF;AAhFD,4CAgFC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenManager.ts
|
|
3
|
+
* Manages session tokens for the Pro Web UI and API server.
|
|
4
|
+
*/
|
|
5
|
+
export declare class TokenManager {
|
|
6
|
+
private tokens;
|
|
7
|
+
private readonly ttlMs;
|
|
8
|
+
constructor(ttlMs?: number);
|
|
9
|
+
/**
|
|
10
|
+
* Generate a new session token.
|
|
11
|
+
*/
|
|
12
|
+
generate(metadata?: Record<string, unknown>): string;
|
|
13
|
+
/**
|
|
14
|
+
* Validate a token. Returns true if valid and not expired.
|
|
15
|
+
*/
|
|
16
|
+
validate(token: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Revoke a token.
|
|
19
|
+
*/
|
|
20
|
+
revoke(token: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Remove all expired tokens.
|
|
23
|
+
*/
|
|
24
|
+
cleanup(): void;
|
|
25
|
+
get activeCount(): number;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=TokenManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenManager.d.ts","sourceRoot":"","sources":["../../../src/pro/auth/TokenManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,KAAK,GAAE,MAA4B;IAI/C;;OAEG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAepD;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAUhC;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI3B;;OAEG;IACH,OAAO,IAAI,IAAI;IAOf,IAAI,WAAW,IAAI,MAAM,CAGxB;CACF"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TokenManager.ts
|
|
4
|
+
* Manages session tokens for the Pro Web UI and API server.
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.TokenManager = void 0;
|
|
41
|
+
const crypto = __importStar(require("crypto"));
|
|
42
|
+
class TokenManager {
|
|
43
|
+
tokens = new Map();
|
|
44
|
+
ttlMs;
|
|
45
|
+
constructor(ttlMs = 24 * 60 * 60 * 1000) {
|
|
46
|
+
this.ttlMs = ttlMs;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate a new session token.
|
|
50
|
+
*/
|
|
51
|
+
generate(metadata) {
|
|
52
|
+
const token = crypto.randomBytes(32).toString('hex');
|
|
53
|
+
const now = Date.now();
|
|
54
|
+
this.tokens.set(token, {
|
|
55
|
+
token,
|
|
56
|
+
createdAt: now,
|
|
57
|
+
expiresAt: now + this.ttlMs,
|
|
58
|
+
metadata,
|
|
59
|
+
});
|
|
60
|
+
this.cleanup();
|
|
61
|
+
return token;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Validate a token. Returns true if valid and not expired.
|
|
65
|
+
*/
|
|
66
|
+
validate(token) {
|
|
67
|
+
const session = this.tokens.get(token);
|
|
68
|
+
if (!session)
|
|
69
|
+
return false;
|
|
70
|
+
if (Date.now() > session.expiresAt) {
|
|
71
|
+
this.tokens.delete(token);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Revoke a token.
|
|
78
|
+
*/
|
|
79
|
+
revoke(token) {
|
|
80
|
+
this.tokens.delete(token);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Remove all expired tokens.
|
|
84
|
+
*/
|
|
85
|
+
cleanup() {
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
for (const [key, session] of this.tokens) {
|
|
88
|
+
if (now > session.expiresAt)
|
|
89
|
+
this.tokens.delete(key);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
get activeCount() {
|
|
93
|
+
this.cleanup();
|
|
94
|
+
return this.tokens.size;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
exports.TokenManager = TokenManager;
|
|
98
|
+
//# sourceMappingURL=TokenManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenManager.js","sourceRoot":"","sources":["../../../src/pro/auth/TokenManager.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,+CAAiC;AASjC,MAAa,YAAY;IACf,MAAM,GAA8B,IAAI,GAAG,EAAE,CAAC;IACrC,KAAK,CAAS;IAE/B,YAAY,QAAgB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;QAC7C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,QAAkC;QACzC,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACrD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE;YACrB,KAAK;YACL,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG,GAAG,IAAI,CAAC,KAAK;YAC3B,QAAQ;SACT,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,KAAa;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAC3B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAa;QAClB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,OAAO;QACL,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACzC,IAAI,GAAG,GAAG,OAAO,CAAC,SAAS;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,IAAI,WAAW;QACb,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IAC1B,CAAC;CACF;AA5DD,oCA4DC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UIServer.ts
|
|
3
|
+
* Local Web UI server (Pro feature).
|
|
4
|
+
* Serves a web dashboard at http://localhost:7777 for interactive log search.
|
|
5
|
+
*/
|
|
6
|
+
import { EventEmitter } from 'events';
|
|
7
|
+
export interface UIServerOptions {
|
|
8
|
+
port?: number;
|
|
9
|
+
host?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class UIServer extends EventEmitter {
|
|
12
|
+
private server;
|
|
13
|
+
private port;
|
|
14
|
+
private host;
|
|
15
|
+
private store;
|
|
16
|
+
private tokenManager;
|
|
17
|
+
constructor(options?: UIServerOptions);
|
|
18
|
+
/**
|
|
19
|
+
* Start the UI server.
|
|
20
|
+
*/
|
|
21
|
+
start(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Stop the UI server.
|
|
24
|
+
*/
|
|
25
|
+
stop(): Promise<void>;
|
|
26
|
+
private handleRequest;
|
|
27
|
+
private handleSearch;
|
|
28
|
+
private handleListIndexes;
|
|
29
|
+
private handleBuildIndex;
|
|
30
|
+
private handleInfo;
|
|
31
|
+
private readBody;
|
|
32
|
+
private renderUI;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=UIServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UIServer.d.ts","sourceRoot":"","sources":["../../../src/pro/webui/UIServer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAMtC,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,QAAS,SAAQ,YAAY;IACxC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,YAAY,CAAe;gBAEvB,OAAO,GAAE,eAAoB;IAQzC;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBtB;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAYP,aAAa;YAqDb,YAAY;YA4BZ,iBAAiB;YAMjB,gBAAgB;YAqBhB,UAAU;IAmBxB,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,QAAQ;CAoJjB"}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* UIServer.ts
|
|
4
|
+
* Local Web UI server (Pro feature).
|
|
5
|
+
* Serves a web dashboard at http://localhost:7777 for interactive log search.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.UIServer = void 0;
|
|
42
|
+
const http = __importStar(require("http"));
|
|
43
|
+
const events_1 = require("events");
|
|
44
|
+
const IndexStore_1 = require("../../index-store/IndexStore");
|
|
45
|
+
const IndexSearcher_1 = require("../../core/searcher/IndexSearcher");
|
|
46
|
+
const IndexBuilder_1 = require("../../core/indexer/IndexBuilder");
|
|
47
|
+
const TokenManager_1 = require("../auth/TokenManager");
|
|
48
|
+
class UIServer extends events_1.EventEmitter {
|
|
49
|
+
server = null;
|
|
50
|
+
port;
|
|
51
|
+
host;
|
|
52
|
+
store;
|
|
53
|
+
tokenManager;
|
|
54
|
+
constructor(options = {}) {
|
|
55
|
+
super();
|
|
56
|
+
this.port = options.port ?? 7777;
|
|
57
|
+
this.host = options.host ?? '127.0.0.1';
|
|
58
|
+
this.store = new IndexStore_1.IndexStore();
|
|
59
|
+
this.tokenManager = new TokenManager_1.TokenManager();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Start the UI server.
|
|
63
|
+
*/
|
|
64
|
+
start() {
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
this.server = http.createServer(this.handleRequest.bind(this));
|
|
67
|
+
this.server.on('error', (err) => {
|
|
68
|
+
this.emit('error', err);
|
|
69
|
+
reject(err);
|
|
70
|
+
});
|
|
71
|
+
this.server.listen(this.port, this.host, () => {
|
|
72
|
+
console.log(`\n🌐 log-search Pro UI: http://${this.host}:${this.port}\n`);
|
|
73
|
+
this.emit('listening', { port: this.port, host: this.host });
|
|
74
|
+
resolve();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Stop the UI server.
|
|
80
|
+
*/
|
|
81
|
+
stop() {
|
|
82
|
+
return new Promise((resolve) => {
|
|
83
|
+
if (this.server) {
|
|
84
|
+
this.server.close(() => resolve());
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
resolve();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
// ─── Request Handler ──────────────────────────────────────────────────────
|
|
92
|
+
async handleRequest(req, res) {
|
|
93
|
+
const url = new URL(req.url ?? '/', `http://${req.headers.host}`);
|
|
94
|
+
const method = req.method ?? 'GET';
|
|
95
|
+
// CORS headers for local dev
|
|
96
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
97
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
98
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
99
|
+
if (method === 'OPTIONS') {
|
|
100
|
+
res.writeHead(204);
|
|
101
|
+
res.end();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
if (url.pathname === '/' || url.pathname === '/index.html') {
|
|
106
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
107
|
+
res.end(this.renderUI());
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (url.pathname === '/api/search' && method === 'POST') {
|
|
111
|
+
await this.handleSearch(req, res);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (url.pathname === '/api/indexes' && method === 'GET') {
|
|
115
|
+
await this.handleListIndexes(res);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (url.pathname === '/api/index' && method === 'POST') {
|
|
119
|
+
await this.handleBuildIndex(req, res);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (url.pathname === '/api/info' && method === 'GET') {
|
|
123
|
+
await this.handleInfo(url, res);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
127
|
+
res.end(JSON.stringify({ error: 'Not Found' }));
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
131
|
+
res.end(JSON.stringify({ error: err instanceof Error ? err.message : 'Internal Error' }));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async handleSearch(req, res) {
|
|
135
|
+
const body = await this.readBody(req);
|
|
136
|
+
const { filePath, query, options = {} } = JSON.parse(body);
|
|
137
|
+
if (!filePath || !query) {
|
|
138
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
139
|
+
res.end(JSON.stringify({ error: 'filePath and query are required' }));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const indexPath = await this.store.getIndexPath(filePath);
|
|
143
|
+
if (!indexPath) {
|
|
144
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
145
|
+
res.end(JSON.stringify({ error: 'Index not found. Build it first.' }));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const searcher = new IndexSearcher_1.IndexSearcher(filePath);
|
|
149
|
+
await searcher.loadIndex(indexPath);
|
|
150
|
+
const t0 = Date.now();
|
|
151
|
+
const results = await searcher.search(query, { limit: 200, ...options });
|
|
152
|
+
const searchTimeMs = Date.now() - t0;
|
|
153
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
154
|
+
res.end(JSON.stringify({ results, totalMatches: results.length, searchTimeMs, query, filePath }));
|
|
155
|
+
}
|
|
156
|
+
async handleListIndexes(res) {
|
|
157
|
+
const entries = await this.store.listAll();
|
|
158
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
159
|
+
res.end(JSON.stringify({ indexes: entries }));
|
|
160
|
+
}
|
|
161
|
+
async handleBuildIndex(req, res) {
|
|
162
|
+
const body = await this.readBody(req);
|
|
163
|
+
const { filePath } = JSON.parse(body);
|
|
164
|
+
if (!filePath) {
|
|
165
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
166
|
+
res.end(JSON.stringify({ error: 'filePath is required' }));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const builder = new IndexBuilder_1.IndexBuilder(filePath);
|
|
170
|
+
const result = await builder.build();
|
|
171
|
+
await this.store.saveIndexPath(filePath, result.indexPath, {
|
|
172
|
+
totalLines: result.totalLines,
|
|
173
|
+
fileSize: result.fileSize,
|
|
174
|
+
});
|
|
175
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
176
|
+
res.end(JSON.stringify(result));
|
|
177
|
+
}
|
|
178
|
+
async handleInfo(url, res) {
|
|
179
|
+
const filePath = url.searchParams.get('file');
|
|
180
|
+
if (!filePath) {
|
|
181
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
182
|
+
res.end(JSON.stringify({ error: 'file parameter required' }));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const info = await this.store.getIndexInfo(filePath);
|
|
186
|
+
if (!info) {
|
|
187
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
188
|
+
res.end(JSON.stringify({ error: 'Index not found' }));
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
192
|
+
res.end(JSON.stringify(info));
|
|
193
|
+
}
|
|
194
|
+
readBody(req) {
|
|
195
|
+
return new Promise((resolve, reject) => {
|
|
196
|
+
const chunks = [];
|
|
197
|
+
req.on('data', (c) => chunks.push(c));
|
|
198
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString()));
|
|
199
|
+
req.on('error', reject);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
// ─── Embedded Web UI ──────────────────────────────────────────────────────
|
|
203
|
+
renderUI() {
|
|
204
|
+
return `<!DOCTYPE html>
|
|
205
|
+
<html lang="en">
|
|
206
|
+
<head>
|
|
207
|
+
<meta charset="UTF-8">
|
|
208
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
209
|
+
<title>log-search Pro UI</title>
|
|
210
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
211
|
+
<style>
|
|
212
|
+
.highlight { background-color: #fef08a; color: #1a1a1a; border-radius: 2px; padding: 0 1px; }
|
|
213
|
+
.line-content { font-family: 'Courier New', monospace; font-size: 0.82rem; }
|
|
214
|
+
pre { white-space: pre-wrap; word-break: break-all; }
|
|
215
|
+
</style>
|
|
216
|
+
</head>
|
|
217
|
+
<body class="bg-gray-950 text-gray-100 min-h-screen">
|
|
218
|
+
<div class="max-w-6xl mx-auto p-6">
|
|
219
|
+
<header class="mb-8">
|
|
220
|
+
<h1 class="text-3xl font-bold text-cyan-400">⚡ log-search <span class="text-purple-400 text-lg">Pro</span></h1>
|
|
221
|
+
<p class="text-gray-400 text-sm mt-1">Search through gigabytes of logs in milliseconds</p>
|
|
222
|
+
</header>
|
|
223
|
+
|
|
224
|
+
<div class="grid grid-cols-1 gap-6">
|
|
225
|
+
<!-- Search Form -->
|
|
226
|
+
<div class="bg-gray-900 rounded-xl p-6 border border-gray-800">
|
|
227
|
+
<div class="flex gap-3 mb-4">
|
|
228
|
+
<input id="file-input" type="text" placeholder="Log file path (e.g., /var/log/nginx/access.log)"
|
|
229
|
+
class="flex-1 bg-gray-800 rounded-lg px-4 py-2 text-sm border border-gray-700 focus:outline-none focus:border-cyan-500">
|
|
230
|
+
<button onclick="buildIndex()" class="bg-purple-600 hover:bg-purple-700 px-4 py-2 rounded-lg text-sm font-medium transition">
|
|
231
|
+
Build Index
|
|
232
|
+
</button>
|
|
233
|
+
</div>
|
|
234
|
+
<div class="flex gap-3">
|
|
235
|
+
<input id="query-input" type="text" placeholder='Search query (e.g., ERROR AND timeout, level:ERROR, ~"connectin")'
|
|
236
|
+
class="flex-1 bg-gray-800 rounded-lg px-4 py-2 text-sm border border-gray-700 focus:outline-none focus:border-cyan-500"
|
|
237
|
+
onkeydown="if(event.key==='Enter') search()">
|
|
238
|
+
<button onclick="search()" class="bg-cyan-600 hover:bg-cyan-700 px-6 py-2 rounded-lg text-sm font-medium transition">
|
|
239
|
+
Search
|
|
240
|
+
</button>
|
|
241
|
+
</div>
|
|
242
|
+
<div class="flex gap-4 mt-3 text-xs text-gray-500">
|
|
243
|
+
<label><input type="checkbox" id="cb-regex" class="mr-1"> Regex</label>
|
|
244
|
+
<label><input type="checkbox" id="cb-case" class="mr-1"> Case Sensitive</label>
|
|
245
|
+
<select id="sel-limit" class="bg-gray-800 rounded px-2 py-1 text-gray-400 text-xs">
|
|
246
|
+
<option value="50">50 results</option>
|
|
247
|
+
<option value="100" selected>100 results</option>
|
|
248
|
+
<option value="500">500 results</option>
|
|
249
|
+
</select>
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<!-- Stats bar -->
|
|
254
|
+
<div id="stats-bar" class="hidden bg-gray-900 rounded-lg px-6 py-3 border border-gray-800 text-sm flex justify-between items-center">
|
|
255
|
+
<span id="stats-text" class="text-gray-400"></span>
|
|
256
|
+
<span id="time-text" class="text-cyan-400 font-mono"></span>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
<!-- Results -->
|
|
260
|
+
<div id="results-container" class="space-y-1"></div>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
<script>
|
|
265
|
+
async function search() {
|
|
266
|
+
const filePath = document.getElementById('file-input').value.trim();
|
|
267
|
+
const query = document.getElementById('query-input').value.trim();
|
|
268
|
+
if (!filePath || !query) { alert('Enter file path and query'); return; }
|
|
269
|
+
|
|
270
|
+
document.getElementById('results-container').innerHTML =
|
|
271
|
+
'<div class="text-center text-gray-500 py-8">Searching...</div>';
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
const res = await fetch('/api/search', {
|
|
275
|
+
method: 'POST',
|
|
276
|
+
headers: { 'Content-Type': 'application/json' },
|
|
277
|
+
body: JSON.stringify({
|
|
278
|
+
filePath, query,
|
|
279
|
+
options: {
|
|
280
|
+
isRegex: document.getElementById('cb-regex').checked,
|
|
281
|
+
ignoreCase: !document.getElementById('cb-case').checked,
|
|
282
|
+
limit: parseInt(document.getElementById('sel-limit').value),
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
});
|
|
286
|
+
const data = await res.json();
|
|
287
|
+
if (data.error) { showError(data.error); return; }
|
|
288
|
+
renderResults(data);
|
|
289
|
+
} catch (err) {
|
|
290
|
+
showError(err.message);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function renderResults(data) {
|
|
295
|
+
const bar = document.getElementById('stats-bar');
|
|
296
|
+
bar.classList.remove('hidden');
|
|
297
|
+
document.getElementById('stats-text').textContent =
|
|
298
|
+
data.totalMatches + ' match' + (data.totalMatches !== 1 ? 'es' : '') + ' found';
|
|
299
|
+
document.getElementById('time-text').textContent =
|
|
300
|
+
data.searchTimeMs.toFixed(1) + 'ms';
|
|
301
|
+
|
|
302
|
+
const container = document.getElementById('results-container');
|
|
303
|
+
if (data.results.length === 0) {
|
|
304
|
+
container.innerHTML = '<div class="text-center text-gray-500 py-12 text-lg">No results found</div>';
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
container.innerHTML = data.results.map((r, i) => \`
|
|
309
|
+
<div class="bg-gray-900 rounded-lg border border-gray-800 hover:border-gray-600 transition overflow-hidden">
|
|
310
|
+
<div class="flex items-center px-4 py-1 bg-gray-800/50 gap-4 text-xs text-gray-500">
|
|
311
|
+
<span class="text-cyan-500 font-mono">#\${i+1}</span>
|
|
312
|
+
<span>Line <strong class="text-gray-300">\${r.lineNumber.toLocaleString()}</strong></span>
|
|
313
|
+
<span class="text-purple-400 font-mono">\${r.matchScore.toFixed(2)}</span>
|
|
314
|
+
</div>
|
|
315
|
+
<pre class="line-content px-4 py-2 text-gray-200">\${escapeHtml(r.content)}</pre>
|
|
316
|
+
</div>
|
|
317
|
+
\`).join('');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async function buildIndex() {
|
|
321
|
+
const filePath = document.getElementById('file-input').value.trim();
|
|
322
|
+
if (!filePath) { alert('Enter a file path'); return; }
|
|
323
|
+
const btn = event.target;
|
|
324
|
+
btn.textContent = 'Building...'; btn.disabled = true;
|
|
325
|
+
try {
|
|
326
|
+
const res = await fetch('/api/index', {
|
|
327
|
+
method: 'POST',
|
|
328
|
+
headers: { 'Content-Type': 'application/json' },
|
|
329
|
+
body: JSON.stringify({ filePath })
|
|
330
|
+
});
|
|
331
|
+
const data = await res.json();
|
|
332
|
+
if (data.error) { showError(data.error); }
|
|
333
|
+
else { alert('Index built! ' + data.totalLines.toLocaleString() + ' lines indexed.'); }
|
|
334
|
+
} finally {
|
|
335
|
+
btn.textContent = 'Build Index'; btn.disabled = false;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function showError(msg) {
|
|
340
|
+
document.getElementById('results-container').innerHTML =
|
|
341
|
+
'<div class="bg-red-900/30 border border-red-700 rounded-lg p-4 text-red-400">' + escapeHtml(msg) + '</div>';
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function escapeHtml(str) {
|
|
345
|
+
return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
346
|
+
}
|
|
347
|
+
</script>
|
|
348
|
+
</body>
|
|
349
|
+
</html>`;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
exports.UIServer = UIServer;
|
|
353
|
+
//# sourceMappingURL=UIServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UIServer.js","sourceRoot":"","sources":["../../../src/pro/webui/UIServer.ts"],"names":[],"mappings":"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"}
|