brew-tui 0.1.0 → 0.2.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/README.md +2 -0
- package/build/{brewbar-installer-CPCOE3MI.js → brewbar-installer-4Z2WE57I.js} +27 -5
- package/build/{chunk-P6PTN4HR.js → chunk-KXDTKY3E.js} +85 -47
- package/build/chunk-UBHTQL7T.js +76 -0
- package/build/{history-logger-LQT622M2.js → history-logger-65UF2R6F.js} +4 -3
- package/build/index.js +207 -115
- package/package.json +2 -2
- package/build/brewbar-installer-CPCOE3MI.js.map +0 -1
- package/build/chunk-3BK3B53S.js +0 -55
- package/build/chunk-3BK3B53S.js.map +0 -1
- package/build/chunk-P6PTN4HR.js.map +0 -1
- package/build/history-logger-LQT622M2.js.map +0 -1
- package/build/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -100,6 +100,8 @@ xcodebuild -workspace BrewBar.xcworkspace -scheme BrewBar build
|
|
|
100
100
|
- **Homebrew** installed on your system
|
|
101
101
|
- **macOS** 14+ (for BrewBar)
|
|
102
102
|
|
|
103
|
+
> **Note:** Brew-TUI is designed for dark terminal backgrounds. Light terminal themes may have reduced visibility.
|
|
104
|
+
|
|
103
105
|
## License
|
|
104
106
|
|
|
105
107
|
[MIT](LICENSE) -- MoLines Designs
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
+
fetchWithTimeout,
|
|
2
3
|
t,
|
|
4
|
+
useLicenseStore,
|
|
3
5
|
verifyPro
|
|
4
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KXDTKY3E.js";
|
|
5
7
|
|
|
6
8
|
// src/lib/brewbar-installer.ts
|
|
7
|
-
import { rm, access } from "fs/promises";
|
|
9
|
+
import { rm, access, readFile } from "fs/promises";
|
|
8
10
|
import { createWriteStream } from "fs";
|
|
11
|
+
import { createHash } from "crypto";
|
|
9
12
|
import { pipeline } from "stream/promises";
|
|
10
13
|
import { execFile } from "child_process";
|
|
11
14
|
import { promisify } from "util";
|
|
@@ -25,19 +28,39 @@ async function installBrewBar(force = false) {
|
|
|
25
28
|
if (process.platform !== "darwin") {
|
|
26
29
|
throw new Error(t("cli_brewbarMacOnly"));
|
|
27
30
|
}
|
|
28
|
-
|
|
31
|
+
const { license, status } = useLicenseStore.getState();
|
|
32
|
+
if (!verifyPro(license, status)) {
|
|
29
33
|
throw new Error(t("cli_brewbarProRequired"));
|
|
30
34
|
}
|
|
31
35
|
if (!force && await isBrewBarInstalled()) {
|
|
32
36
|
throw new Error(t("cli_brewbarAlreadyInstalled"));
|
|
33
37
|
}
|
|
34
38
|
console.log(t("cli_brewbarInstalling"));
|
|
35
|
-
const res = await
|
|
39
|
+
const res = await fetchWithTimeout(DOWNLOAD_URL, {}, 12e4);
|
|
36
40
|
if (!res.ok || !res.body) {
|
|
37
41
|
throw new Error(t("cli_brewbarDownloadFailed", { error: `HTTP ${res.status}` }));
|
|
38
42
|
}
|
|
43
|
+
const contentLength = Number(res.headers.get("content-length") ?? "0");
|
|
44
|
+
if (contentLength > 200 * 1024 * 1024) {
|
|
45
|
+
throw new Error(t("cli_brewbarDownloadFailed", { error: "Download exceeds 200 MB size limit" }));
|
|
46
|
+
}
|
|
39
47
|
const fileStream = createWriteStream(TMP_ZIP);
|
|
40
48
|
await pipeline(res.body, fileStream);
|
|
49
|
+
try {
|
|
50
|
+
const checksumRes = await fetchWithTimeout(`${DOWNLOAD_URL}.sha256`, {}, 15e3);
|
|
51
|
+
if (checksumRes.ok) {
|
|
52
|
+
const expected = (await checksumRes.text()).trim().split(/\s+/)[0].toLowerCase();
|
|
53
|
+
const fileBuffer = await readFile(TMP_ZIP);
|
|
54
|
+
const actual = createHash("sha256").update(fileBuffer).digest("hex");
|
|
55
|
+
if (actual !== expected) {
|
|
56
|
+
await rm(TMP_ZIP, { force: true }).catch(() => {
|
|
57
|
+
});
|
|
58
|
+
throw new Error(t("cli_brewbarDownloadFailed", { error: "SHA-256 checksum mismatch" }));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} catch (err) {
|
|
62
|
+
if (err instanceof Error && err.message.includes("checksum mismatch")) throw err;
|
|
63
|
+
}
|
|
41
64
|
if (force && await isBrewBarInstalled()) {
|
|
42
65
|
await rm(BREWBAR_APP_PATH, { recursive: true, force: true });
|
|
43
66
|
}
|
|
@@ -61,4 +84,3 @@ export {
|
|
|
61
84
|
isBrewBarInstalled,
|
|
62
85
|
uninstallBrewBar
|
|
63
86
|
};
|
|
64
|
-
//# sourceMappingURL=brewbar-installer-CPCOE3MI.js.map
|
|
@@ -231,13 +231,13 @@ var en = {
|
|
|
231
231
|
account_nameLabel: "Name:",
|
|
232
232
|
account_planLabel: "Plan:",
|
|
233
233
|
account_monthlyPrice: "9\u20AC/month",
|
|
234
|
-
|
|
234
|
+
account_lifetimePrice: "29\u20AC lifetime",
|
|
235
235
|
account_keyLabel: "Key:",
|
|
236
236
|
account_expiresLabel: "Expires:",
|
|
237
237
|
account_activatedLabel: "Activated:",
|
|
238
238
|
account_upgradeTitle: "Upgrade to Brew-TUI Pro",
|
|
239
239
|
account_unlockDesc: "Unlock Profiles, Smart Cleanup, History, Security Audit, and BrewBar (macOS menu bar companion).",
|
|
240
|
-
account_pricing: "9\u20AC/month or
|
|
240
|
+
account_pricing: "9\u20AC/month or 29\u20AC lifetime",
|
|
241
241
|
account_runActivate: "Run:",
|
|
242
242
|
account_activateCmd: "brew-tui activate <key>",
|
|
243
243
|
account_licenseExpired: "Your license has expired. Renew to continue using Pro features.",
|
|
@@ -252,10 +252,12 @@ var en = {
|
|
|
252
252
|
upgrade_historyDesc: "Track every install, uninstall, and upgrade with timestamps. Search and filter your package management history.",
|
|
253
253
|
upgrade_security: "Security Audit",
|
|
254
254
|
upgrade_securityDesc: "Scan installed packages against known vulnerabilities (CVEs). See severity levels, affected versions, and available fixes.",
|
|
255
|
-
upgrade_pricing: "9\u20AC/month or
|
|
256
|
-
|
|
255
|
+
upgrade_pricing: "9\u20AC/month or 29\u20AC lifetime",
|
|
256
|
+
upgrade_buyAt: "Buy at:",
|
|
257
|
+
upgrade_buyUrl: "https://buy.polar.sh/polar_cl_QW1ZJ9887bU74drGr7JfujQfm3RKYnn1fuvc53DqD6D",
|
|
258
|
+
upgrade_activateWith: "Then activate with:",
|
|
257
259
|
upgrade_activateCmd: "brew-tui activate <your-license-key>",
|
|
258
|
-
upgrade_proLabel: "Brew-TUI Pro \u2014 9\u20AC/month or
|
|
260
|
+
upgrade_proLabel: "Brew-TUI Pro \u2014 9\u20AC/month or 29\u20AC lifetime \u2014 Includes BrewBar for macOS",
|
|
259
261
|
// ── Progress Log ──
|
|
260
262
|
progress_noOutput: "No output yet",
|
|
261
263
|
// ── Search Input ──
|
|
@@ -290,6 +292,7 @@ var en = {
|
|
|
290
292
|
cli_brewbarProRequired: "\u2718 BrewBar requires a Pro license.\n Run: brew-tui activate <key>",
|
|
291
293
|
cli_brewbarMacOnly: "\u2718 BrewBar is only available on macOS.",
|
|
292
294
|
cli_brewbarDownloadFailed: "\u2718 Failed to download BrewBar: {{error}}",
|
|
295
|
+
cli_deactivateRemoteFailed: "\u26A0 Warning: Could not reach the server to deactivate remotely. The license was removed locally but may still count as active.",
|
|
293
296
|
// ── License degradation (Layer 15) ──
|
|
294
297
|
license_offlineWarning: "Your license has not been validated for {{days}} days. Please connect to the internet.",
|
|
295
298
|
// ── Plurals ──
|
|
@@ -533,13 +536,13 @@ var es = {
|
|
|
533
536
|
account_nameLabel: "Nombre:",
|
|
534
537
|
account_planLabel: "Plan:",
|
|
535
538
|
account_monthlyPrice: "9\u20AC/mes",
|
|
536
|
-
|
|
539
|
+
account_lifetimePrice: "29\u20AC de por vida",
|
|
537
540
|
account_keyLabel: "Clave:",
|
|
538
541
|
account_expiresLabel: "Expira:",
|
|
539
542
|
account_activatedLabel: "Activado:",
|
|
540
543
|
account_upgradeTitle: "Actualiza a Brew-TUI Pro",
|
|
541
544
|
account_unlockDesc: "Desbloquea Perfiles, Limpieza Inteligente, Historial, Auditor\xEDa de Seguridad y BrewBar (barra de men\xFA macOS).",
|
|
542
|
-
account_pricing: "9\u20AC/mes o
|
|
545
|
+
account_pricing: "9\u20AC/mes o 29\u20AC de por vida",
|
|
543
546
|
account_runActivate: "Ejecuta:",
|
|
544
547
|
account_activateCmd: "brew-tui activate <clave>",
|
|
545
548
|
account_licenseExpired: "Tu licencia ha expirado. Renueva para seguir usando las funciones Pro.",
|
|
@@ -554,10 +557,12 @@ var es = {
|
|
|
554
557
|
upgrade_historyDesc: "Rastrea cada instalaci\xF3n, desinstalaci\xF3n y actualizaci\xF3n con marcas de tiempo. Busca y filtra tu historial de gesti\xF3n de paquetes.",
|
|
555
558
|
upgrade_security: "Auditor\xEDa de Seguridad",
|
|
556
559
|
upgrade_securityDesc: "Escanea paquetes instalados contra vulnerabilidades conocidas (CVEs). Ve niveles de severidad, versiones afectadas y correcciones disponibles.",
|
|
557
|
-
upgrade_pricing: "9\u20AC/mes o
|
|
558
|
-
|
|
560
|
+
upgrade_pricing: "9\u20AC/mes o 29\u20AC de por vida",
|
|
561
|
+
upgrade_buyAt: "Compra en:",
|
|
562
|
+
upgrade_buyUrl: "https://buy.polar.sh/polar_cl_QW1ZJ9887bU74drGr7JfujQfm3RKYnn1fuvc53DqD6D",
|
|
563
|
+
upgrade_activateWith: "Luego activa con:",
|
|
559
564
|
upgrade_activateCmd: "brew-tui activate <tu-clave-de-licencia>",
|
|
560
|
-
upgrade_proLabel: "Brew-TUI Pro \u2014 9\u20AC/mes o
|
|
565
|
+
upgrade_proLabel: "Brew-TUI Pro \u2014 9\u20AC/mes o 29\u20AC de por vida \u2014 Incluye BrewBar para macOS",
|
|
561
566
|
// ── Progress Log ──
|
|
562
567
|
progress_noOutput: "Sin salida a\xFAn",
|
|
563
568
|
// ── Search Input ──
|
|
@@ -592,6 +597,7 @@ var es = {
|
|
|
592
597
|
cli_brewbarProRequired: "\u2718 BrewBar requiere una licencia Pro.\n Ejecuta: brew-tui activate <clave>",
|
|
593
598
|
cli_brewbarMacOnly: "\u2718 BrewBar solo est\xE1 disponible en macOS.",
|
|
594
599
|
cli_brewbarDownloadFailed: "\u2718 Error al descargar BrewBar: {{error}}",
|
|
600
|
+
cli_deactivateRemoteFailed: "\u26A0 Advertencia: No se pudo contactar al servidor para desactivar remotamente. La licencia se elimin\xF3 localmente pero puede seguir contando como activa.",
|
|
595
601
|
// ── License degradation (Layer 15) ──
|
|
596
602
|
license_offlineWarning: "Tu licencia no se ha validado en {{days}} d\xEDas. Por favor con\xE9ctate a internet.",
|
|
597
603
|
// ── Plurals ──
|
|
@@ -649,12 +655,17 @@ var PROFILES_DIR = join(DATA_DIR, "profiles");
|
|
|
649
655
|
var LICENSE_PATH = join(DATA_DIR, "license.json");
|
|
650
656
|
var HISTORY_PATH = join(DATA_DIR, "history.json");
|
|
651
657
|
async function ensureDataDirs() {
|
|
652
|
-
await mkdir(DATA_DIR, { recursive: true });
|
|
653
|
-
await mkdir(PROFILES_DIR, { recursive: true });
|
|
658
|
+
await mkdir(DATA_DIR, { recursive: true, mode: 448 });
|
|
659
|
+
await mkdir(PROFILES_DIR, { recursive: true, mode: 448 });
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// src/lib/fetch-timeout.ts
|
|
663
|
+
function fetchWithTimeout(url, options = {}, timeoutMs = 15e3) {
|
|
664
|
+
return fetch(url, { ...options, signal: AbortSignal.timeout(timeoutMs) });
|
|
654
665
|
}
|
|
655
666
|
|
|
656
667
|
// src/lib/license/license-manager.ts
|
|
657
|
-
import { readFile, writeFile, rm } from "fs/promises";
|
|
668
|
+
import { readFile, writeFile, rename, rm } from "fs/promises";
|
|
658
669
|
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "crypto";
|
|
659
670
|
|
|
660
671
|
// src/lib/license/polar-api.ts
|
|
@@ -673,11 +684,11 @@ function validateApiUrl(url) {
|
|
|
673
684
|
async function post(endpoint, body, expectEmpty = false) {
|
|
674
685
|
const url = `${BASE_URL}/${endpoint}`;
|
|
675
686
|
validateApiUrl(url);
|
|
676
|
-
const res = await
|
|
687
|
+
const res = await fetchWithTimeout(url, {
|
|
677
688
|
method: "POST",
|
|
678
689
|
headers: { "Content-Type": "application/json" },
|
|
679
690
|
body: JSON.stringify(body)
|
|
680
|
-
});
|
|
691
|
+
}, 15e3);
|
|
681
692
|
if (!res.ok) {
|
|
682
693
|
let message = `Request failed with status ${res.status}`;
|
|
683
694
|
try {
|
|
@@ -789,8 +800,9 @@ function recordAttempt(success) {
|
|
|
789
800
|
}
|
|
790
801
|
var ENCRYPTION_SECRET = "brew-tui-license-aes256gcm-v1";
|
|
791
802
|
var SCRYPT_SALT = "brew-tui-salt-v1";
|
|
792
|
-
var _derivedKey =
|
|
803
|
+
var _derivedKey = null;
|
|
793
804
|
function deriveEncryptionKey() {
|
|
805
|
+
if (!_derivedKey) _derivedKey = scryptSync(ENCRYPTION_SECRET, SCRYPT_SALT, 32);
|
|
794
806
|
return _derivedKey;
|
|
795
807
|
}
|
|
796
808
|
function encryptLicenseData(data) {
|
|
@@ -824,6 +836,9 @@ async function loadLicense() {
|
|
|
824
836
|
try {
|
|
825
837
|
const raw = await readFile(LICENSE_PATH, "utf-8");
|
|
826
838
|
const file = JSON.parse(raw);
|
|
839
|
+
if (file.version !== 1) {
|
|
840
|
+
throw new Error("Unsupported data version");
|
|
841
|
+
}
|
|
827
842
|
if (file.encrypted && file.iv && file.tag) {
|
|
828
843
|
const data = decryptLicenseData(file.encrypted, file.iv, file.tag);
|
|
829
844
|
return data;
|
|
@@ -842,7 +857,9 @@ async function saveLicense(data) {
|
|
|
842
857
|
await ensureDataDirs();
|
|
843
858
|
const { encrypted, iv, tag } = encryptLicenseData(data);
|
|
844
859
|
const file = { version: 1, encrypted, iv, tag };
|
|
845
|
-
|
|
860
|
+
const tmpPath = LICENSE_PATH + ".tmp";
|
|
861
|
+
await writeFile(tmpPath, JSON.stringify(file, null, 2), { encoding: "utf-8", mode: 384 });
|
|
862
|
+
await rename(tmpPath, LICENSE_PATH);
|
|
846
863
|
}
|
|
847
864
|
async function clearLicense() {
|
|
848
865
|
try {
|
|
@@ -930,23 +947,52 @@ async function revalidate(license) {
|
|
|
930
947
|
}
|
|
931
948
|
}
|
|
932
949
|
async function deactivate(license) {
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
950
|
+
let remoteSuccess = false;
|
|
951
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
952
|
+
try {
|
|
953
|
+
await deactivateLicense(license.key, license.instanceId);
|
|
954
|
+
remoteSuccess = true;
|
|
955
|
+
break;
|
|
956
|
+
} catch {
|
|
957
|
+
if (attempt < 2) await new Promise((r) => setTimeout(r, 1e3));
|
|
958
|
+
}
|
|
936
959
|
}
|
|
937
960
|
await clearLicense();
|
|
961
|
+
return { remoteSuccess };
|
|
938
962
|
}
|
|
939
963
|
|
|
940
964
|
// src/stores/license-store.ts
|
|
941
965
|
import { create as create2 } from "zustand";
|
|
966
|
+
|
|
967
|
+
// src/lib/license/anti-tamper.ts
|
|
968
|
+
var _originalIsPro = null;
|
|
969
|
+
var _originalGetState = null;
|
|
970
|
+
var _storeApi = null;
|
|
971
|
+
function initStoreIntegrity(store) {
|
|
972
|
+
_storeApi = store;
|
|
973
|
+
_originalIsPro = store.getState().isPro;
|
|
974
|
+
_originalGetState = store.getState;
|
|
975
|
+
}
|
|
976
|
+
function verifyStoreIntegrity() {
|
|
977
|
+
if (!_storeApi || !_originalIsPro || !_originalGetState) return false;
|
|
978
|
+
const state = _storeApi.getState();
|
|
979
|
+
if (state.isPro !== _originalIsPro) return false;
|
|
980
|
+
if (_storeApi.getState !== _originalGetState) return false;
|
|
981
|
+
if (state.status === "free" && state.isPro()) return false;
|
|
982
|
+
return true;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// src/stores/license-store.ts
|
|
942
986
|
var REVALIDATION_CHECK_MS = 60 * 60 * 1e3;
|
|
943
987
|
var _revalidating = false;
|
|
988
|
+
var _revalidationInterval = null;
|
|
944
989
|
var useLicenseStore = create2((set, get) => ({
|
|
945
|
-
status: "
|
|
990
|
+
status: "validating",
|
|
946
991
|
license: null,
|
|
947
992
|
error: null,
|
|
948
993
|
degradation: "none",
|
|
949
994
|
initialize: async () => {
|
|
995
|
+
initStoreIntegrity(useLicenseStore);
|
|
950
996
|
await ensureDataDirs();
|
|
951
997
|
const license = await loadLicense();
|
|
952
998
|
if (!license) {
|
|
@@ -977,7 +1023,8 @@ var useLicenseStore = create2((set, get) => ({
|
|
|
977
1023
|
_revalidating = false;
|
|
978
1024
|
}
|
|
979
1025
|
}
|
|
980
|
-
|
|
1026
|
+
if (_revalidationInterval) clearInterval(_revalidationInterval);
|
|
1027
|
+
_revalidationInterval = setInterval(async () => {
|
|
981
1028
|
const current = get().license;
|
|
982
1029
|
if (!current || get().status !== "pro") return;
|
|
983
1030
|
if (!needsRevalidation(current)) return;
|
|
@@ -994,7 +1041,8 @@ var useLicenseStore = create2((set, get) => ({
|
|
|
994
1041
|
} finally {
|
|
995
1042
|
_revalidating = false;
|
|
996
1043
|
}
|
|
997
|
-
}, REVALIDATION_CHECK_MS)
|
|
1044
|
+
}, REVALIDATION_CHECK_MS);
|
|
1045
|
+
_revalidationInterval.unref();
|
|
998
1046
|
},
|
|
999
1047
|
activate: async (key) => {
|
|
1000
1048
|
set({ error: null });
|
|
@@ -1011,7 +1059,11 @@ var useLicenseStore = create2((set, get) => ({
|
|
|
1011
1059
|
deactivate: async () => {
|
|
1012
1060
|
const { license } = get();
|
|
1013
1061
|
if (license) {
|
|
1014
|
-
await deactivate(license);
|
|
1062
|
+
const { remoteSuccess } = await deactivate(license);
|
|
1063
|
+
if (!remoteSuccess) {
|
|
1064
|
+
set({ status: "free", license: null, error: "License removed locally but server deactivation failed. It may remain active remotely." });
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1015
1067
|
}
|
|
1016
1068
|
set({ status: "free", license: null, error: null });
|
|
1017
1069
|
},
|
|
@@ -1021,24 +1073,13 @@ var useLicenseStore = create2((set, get) => ({
|
|
|
1021
1073
|
// src/lib/license/anti-debug.ts
|
|
1022
1074
|
import inspector from "inspector";
|
|
1023
1075
|
function isDebuggerAttached() {
|
|
1024
|
-
if (
|
|
1076
|
+
if (false) return false;
|
|
1025
1077
|
if (inspector.url()) return true;
|
|
1026
1078
|
if (process.execArgv.some((a) => a.includes("--inspect") || a.includes("--debug"))) return true;
|
|
1027
1079
|
if (process.env.NODE_OPTIONS?.includes("--inspect")) return true;
|
|
1028
1080
|
return false;
|
|
1029
1081
|
}
|
|
1030
1082
|
|
|
1031
|
-
// src/lib/license/anti-tamper.ts
|
|
1032
|
-
var _originalIsPro = useLicenseStore.getState().isPro;
|
|
1033
|
-
var _originalGetState = useLicenseStore.getState;
|
|
1034
|
-
function verifyStoreIntegrity() {
|
|
1035
|
-
const state = useLicenseStore.getState();
|
|
1036
|
-
if (state.isPro !== _originalIsPro) return false;
|
|
1037
|
-
if (useLicenseStore.getState !== _originalGetState) return false;
|
|
1038
|
-
if (state.status === "free" && state.isPro()) return false;
|
|
1039
|
-
return true;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
1083
|
// src/lib/license/canary.ts
|
|
1043
1084
|
var _canaryTripped = false;
|
|
1044
1085
|
function isProUnlocked() {
|
|
@@ -1096,29 +1137,26 @@ function checkBundleIntegrity() {
|
|
|
1096
1137
|
}
|
|
1097
1138
|
|
|
1098
1139
|
// src/lib/license/pro-guard.ts
|
|
1099
|
-
var _S = String.fromCharCode(115, 116, 97, 116, 117, 115);
|
|
1100
1140
|
var _P = String.fromCharCode(112, 114, 111);
|
|
1101
|
-
function _verify() {
|
|
1102
|
-
|
|
1103
|
-
return state[_S] === _P;
|
|
1141
|
+
function _verify(status) {
|
|
1142
|
+
return status === _P;
|
|
1104
1143
|
}
|
|
1105
|
-
function verifyPro() {
|
|
1144
|
+
function verifyPro(license, status) {
|
|
1106
1145
|
if (isDebuggerAttached()) return false;
|
|
1107
1146
|
if (!checkBundleIntegrity()) return false;
|
|
1108
1147
|
if (!verifyStoreIntegrity()) return false;
|
|
1109
1148
|
if (!checkCanaries()) return false;
|
|
1110
|
-
const directCheck =
|
|
1111
|
-
const indirectCheck = _verify();
|
|
1149
|
+
const directCheck = status === "pro";
|
|
1150
|
+
const indirectCheck = _verify(status);
|
|
1112
1151
|
if (!directCheck || !indirectCheck) return false;
|
|
1113
|
-
const license = useLicenseStore.getState().license;
|
|
1114
1152
|
if (license) {
|
|
1115
1153
|
const level = getDegradationLevel(license);
|
|
1116
1154
|
if (level === "expired" || level === "limited") return false;
|
|
1117
1155
|
}
|
|
1118
1156
|
return true;
|
|
1119
1157
|
}
|
|
1120
|
-
function requirePro() {
|
|
1121
|
-
if (!verifyPro()) {
|
|
1158
|
+
function requirePro(license, status) {
|
|
1159
|
+
if (!verifyPro(license, status)) {
|
|
1122
1160
|
throw new Error("Pro license required");
|
|
1123
1161
|
}
|
|
1124
1162
|
}
|
|
@@ -1130,6 +1168,7 @@ export {
|
|
|
1130
1168
|
PROFILES_DIR,
|
|
1131
1169
|
HISTORY_PATH,
|
|
1132
1170
|
ensureDataDirs,
|
|
1171
|
+
fetchWithTimeout,
|
|
1133
1172
|
loadLicense,
|
|
1134
1173
|
activate,
|
|
1135
1174
|
deactivate,
|
|
@@ -1137,4 +1176,3 @@ export {
|
|
|
1137
1176
|
verifyPro,
|
|
1138
1177
|
requirePro
|
|
1139
1178
|
};
|
|
1140
|
-
//# sourceMappingURL=chunk-P6PTN4HR.js.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HISTORY_PATH,
|
|
3
|
+
ensureDataDirs,
|
|
4
|
+
requirePro,
|
|
5
|
+
useLicenseStore
|
|
6
|
+
} from "./chunk-KXDTKY3E.js";
|
|
7
|
+
|
|
8
|
+
// src/lib/history/history-logger.ts
|
|
9
|
+
import { readFile, writeFile, rename } from "fs/promises";
|
|
10
|
+
import { randomUUID } from "crypto";
|
|
11
|
+
var MAX_ENTRIES = 1e3;
|
|
12
|
+
function detectAction(args) {
|
|
13
|
+
const cmd = args[0];
|
|
14
|
+
if (cmd === "install") return { action: "install", packageName: args[1] ?? null };
|
|
15
|
+
if (cmd === "uninstall") {
|
|
16
|
+
const name = args.find((a) => !a.startsWith("-")) === "uninstall" ? args.find((a, i) => i > 0 && !a.startsWith("-")) ?? null : args[1] ?? null;
|
|
17
|
+
return { action: "uninstall", packageName: name };
|
|
18
|
+
}
|
|
19
|
+
if (cmd === "upgrade") {
|
|
20
|
+
if (args.length === 1) return { action: "upgrade-all", packageName: null };
|
|
21
|
+
return { action: "upgrade", packageName: args[1] ?? null };
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
async function loadHistory() {
|
|
26
|
+
const { license, status } = useLicenseStore.getState();
|
|
27
|
+
requirePro(license, status);
|
|
28
|
+
try {
|
|
29
|
+
const raw = await readFile(HISTORY_PATH, "utf-8");
|
|
30
|
+
const file = JSON.parse(raw);
|
|
31
|
+
if (file.version !== 1) {
|
|
32
|
+
throw new Error("Unsupported data version");
|
|
33
|
+
}
|
|
34
|
+
const entries = file.entries;
|
|
35
|
+
return Array.isArray(entries) ? entries : [];
|
|
36
|
+
} catch {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function saveHistory(entries) {
|
|
41
|
+
await ensureDataDirs();
|
|
42
|
+
const file = { version: 1, entries };
|
|
43
|
+
const tmp = HISTORY_PATH + ".tmp";
|
|
44
|
+
await writeFile(tmp, JSON.stringify(file, null, 2), { encoding: "utf-8", mode: 384 });
|
|
45
|
+
await rename(tmp, HISTORY_PATH);
|
|
46
|
+
}
|
|
47
|
+
async function appendEntry(action, packageName, success, error = null) {
|
|
48
|
+
const { license, status } = useLicenseStore.getState();
|
|
49
|
+
requirePro(license, status);
|
|
50
|
+
const entries = await loadHistory();
|
|
51
|
+
const entry = {
|
|
52
|
+
id: randomUUID(),
|
|
53
|
+
action,
|
|
54
|
+
packageName,
|
|
55
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
56
|
+
success,
|
|
57
|
+
error
|
|
58
|
+
};
|
|
59
|
+
entries.unshift(entry);
|
|
60
|
+
if (entries.length > MAX_ENTRIES) {
|
|
61
|
+
entries.length = MAX_ENTRIES;
|
|
62
|
+
}
|
|
63
|
+
await saveHistory(entries);
|
|
64
|
+
}
|
|
65
|
+
async function clearHistory() {
|
|
66
|
+
const { license, status } = useLicenseStore.getState();
|
|
67
|
+
requirePro(license, status);
|
|
68
|
+
await saveHistory([]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export {
|
|
72
|
+
detectAction,
|
|
73
|
+
loadHistory,
|
|
74
|
+
appendEntry,
|
|
75
|
+
clearHistory
|
|
76
|
+
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
appendEntry,
|
|
3
3
|
clearHistory,
|
|
4
|
+
detectAction,
|
|
4
5
|
loadHistory
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-UBHTQL7T.js";
|
|
7
|
+
import "./chunk-KXDTKY3E.js";
|
|
7
8
|
export {
|
|
8
9
|
appendEntry,
|
|
9
10
|
clearHistory,
|
|
11
|
+
detectAction,
|
|
10
12
|
loadHistory
|
|
11
13
|
};
|
|
12
|
-
//# sourceMappingURL=history-logger-LQT622M2.js.map
|