brew-tui 0.6.1 → 0.6.2

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 (38) hide show
  1. package/README.md +5 -5
  2. package/build/{brewbar-installer-BAHS6EEZ.js → brewbar-installer-WJZKSELD.js} +3 -3
  3. package/build/brewbar-installer-WJZKSELD.js.map +1 -0
  4. package/build/{brewfile-manager-3SERRYNC.js → brewfile-manager-OITSKEHY.js} +4 -4
  5. package/build/{chunk-U2DRWB7A.js → chunk-5MYWF5D7.js} +2 -2
  6. package/build/{chunk-MSXH66I2.js → chunk-6NA4INJS.js} +31 -3
  7. package/build/chunk-6NA4INJS.js.map +1 -0
  8. package/build/chunk-EHIBIFCB.js +54 -0
  9. package/build/chunk-EHIBIFCB.js.map +1 -0
  10. package/build/{chunk-LXF72RCD.js → chunk-KSIAKLE2.js} +3 -3
  11. package/build/{chunk-4I344KQX.js → chunk-PVSE6XO7.js} +42 -2
  12. package/build/chunk-PVSE6XO7.js.map +1 -0
  13. package/build/chunk-QPXROTAP.js +679 -0
  14. package/build/chunk-QPXROTAP.js.map +1 -0
  15. package/build/{chunk-KVCVIRWI.js → chunk-Z2VN4VYQ.js} +2 -2
  16. package/build/compliance-checker-7NMFKWTI.js +12 -0
  17. package/build/{history-logger-PBDOLKNJ.js → history-logger-ZGYRAFON.js} +3 -3
  18. package/build/index.js +449 -678
  19. package/build/index.js.map +1 -1
  20. package/build/{snapshot-RAPGMAJF.js → snapshot-YWIOFQ5H.js} +7 -3
  21. package/build/{sync-engine-CAFK4LHA.js → sync-engine-DIYXV66P.js} +7 -5
  22. package/package.json +4 -4
  23. package/build/brewbar-installer-BAHS6EEZ.js.map +0 -1
  24. package/build/chunk-4I344KQX.js.map +0 -1
  25. package/build/chunk-AIAZQJKL.js +0 -299
  26. package/build/chunk-AIAZQJKL.js.map +0 -1
  27. package/build/chunk-MSXH66I2.js.map +0 -1
  28. package/build/chunk-UWS4A4F5.js +0 -25
  29. package/build/chunk-UWS4A4F5.js.map +0 -1
  30. package/build/compliance-checker-X7P623UF.js +0 -12
  31. /package/build/{brewfile-manager-3SERRYNC.js.map → brewfile-manager-OITSKEHY.js.map} +0 -0
  32. /package/build/{chunk-U2DRWB7A.js.map → chunk-5MYWF5D7.js.map} +0 -0
  33. /package/build/{chunk-LXF72RCD.js.map → chunk-KSIAKLE2.js.map} +0 -0
  34. /package/build/{chunk-KVCVIRWI.js.map → chunk-Z2VN4VYQ.js.map} +0 -0
  35. /package/build/{compliance-checker-X7P623UF.js.map → compliance-checker-7NMFKWTI.js.map} +0 -0
  36. /package/build/{history-logger-PBDOLKNJ.js.map → history-logger-ZGYRAFON.js.map} +0 -0
  37. /package/build/{snapshot-RAPGMAJF.js.map → snapshot-YWIOFQ5H.js.map} +0 -0
  38. /package/build/{sync-engine-CAFK4LHA.js.map → sync-engine-DIYXV66P.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/sync/sync-engine.ts","../src/lib/sync/crypto.ts","../src/lib/sync/backends/icloud-backend.ts","../src/lib/license/license-manager.ts","../src/lib/license/polar-api.ts"],"sourcesContent":["import { readFile, writeFile, rename } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { hostname } from 'node:os';\nimport { encryptPayload, decryptPayload } from './crypto.js';\nimport {\n readSyncEnvelope,\n writeSyncEnvelope,\n isICloudAvailable,\n} from './backends/icloud-backend.js';\nimport { captureSnapshot } from '../state-snapshot/snapshot.js';\nimport { DATA_DIR, getMachineId } from '../data-dir.js';\nimport { loadLicense } from '../license/license-manager.js';\nimport { logger } from '../../utils/logger.js';\nimport type {\n SyncConfig,\n SyncPayload,\n SyncConflict,\n SyncResult,\n MachineState,\n SyncEnvelope,\n} from './types.js';\nimport type { BrewfileSchema } from '../brewfile/types.js';\n\nconst SYNC_CONFIG_PATH = join(DATA_DIR, 'sync-config.json');\n\n// ── Config I/O ──────────────────────────────────────────────────────────────\n\nexport async function loadSyncConfig(): Promise<SyncConfig | null> {\n try {\n const raw = await readFile(SYNC_CONFIG_PATH, 'utf-8');\n return JSON.parse(raw) as SyncConfig;\n } catch {\n return null;\n }\n}\n\nexport async function saveSyncConfig(config: SyncConfig): Promise<void> {\n const tmpPath = SYNC_CONFIG_PATH + '.tmp';\n await writeFile(tmpPath, JSON.stringify(config, null, 2), {\n encoding: 'utf-8',\n mode: 0o600,\n });\n await rename(tmpPath, SYNC_CONFIG_PATH);\n}\n\n// ── Machine ID ───────────────────────────────────────────────────────────────\n// Single canonical implementation lives in data-dir.ts. The previous fallback\n// to os.hostname() here meant two different machines with the same hostname\n// (common on freshly-imaged corporate fleets) collided in sync state.\n\nexport { getMachineId };\n\n// ── Conflict detection ───────────────────────────────────────────────────────\n\nfunction detectConflicts(\n localSnapshot: { formulae: Array<{ name: string; version: string }>; casks: Array<{ name: string; version: string }> },\n otherMachines: MachineState[],\n localMachineId: string,\n): SyncConflict[] {\n const conflicts: SyncConflict[] = [];\n\n const localFormulaMap = new Map(localSnapshot.formulae.map((f) => [f.name, f.version]));\n const localCaskMap = new Map(localSnapshot.casks.map((c) => [c.name, c.version]));\n\n for (const machine of otherMachines) {\n if (machine.machineId === localMachineId) continue;\n\n // Check formula conflicts: same package, different version on both machines\n for (const remoteFormula of machine.snapshot.formulae) {\n const localVersion = localFormulaMap.get(remoteFormula.name);\n if (localVersion !== undefined && localVersion !== remoteFormula.version) {\n conflicts.push({\n packageName: remoteFormula.name,\n packageType: 'formula',\n localVersion,\n remoteMachine: machine.machineName,\n remoteVersion: remoteFormula.version,\n });\n }\n }\n\n // Check cask conflicts\n for (const remoteCask of machine.snapshot.casks) {\n const localVersion = localCaskMap.get(remoteCask.name);\n if (localVersion !== undefined && localVersion !== remoteCask.version) {\n conflicts.push({\n packageName: remoteCask.name,\n packageType: 'cask',\n localVersion,\n remoteMachine: machine.machineName,\n remoteVersion: remoteCask.version,\n });\n }\n }\n }\n\n return conflicts;\n}\n\n// ── Merge ────────────────────────────────────────────────────────────────────\n\nasync function writeEnvelope(payload: SyncPayload, licenseKey: string): Promise<string> {\n const now = new Date().toISOString();\n const { encrypted, iv, tag } = encryptPayload(payload, licenseKey);\n const envelope: SyncEnvelope = {\n schemaVersion: 1,\n encrypted,\n iv,\n tag,\n updatedAt: now,\n };\n await writeSyncEnvelope(envelope);\n return now;\n}\n\nasync function loadLicenseKeyOrThrow(): Promise<string> {\n // Sync requires Pro, and Pro requires a license. Read it lazily so\n // sync-store callers don't have to plumb the key through every call.\n const license = await loadLicense();\n if (!license || !license.key) {\n throw new Error('Sync requires an active license');\n }\n return license.key;\n}\n\nfunction mergePayload(existing: SyncPayload, localState: MachineState): SyncPayload {\n return {\n machines: {\n ...existing.machines,\n [localState.machineId]: localState,\n },\n };\n}\n\n// ── Main sync function ───────────────────────────────────────────────────────\n\nexport async function sync(\n isPro: boolean,\n currentBrewfile?: BrewfileSchema,\n): Promise<SyncResult> {\n if (!isPro) {\n throw new Error('Pro license required');\n }\n\n const available = await isICloudAvailable();\n if (!available) {\n return {\n success: false,\n conflicts: [],\n resolvedCount: 0,\n error: 'iCloud Drive not available',\n };\n }\n\n const licenseKey = await loadLicenseKeyOrThrow();\n\n let existingPayload: SyncPayload | null = null;\n\n try {\n const envelope = await readSyncEnvelope();\n if (envelope) {\n existingPayload = decryptPayload(envelope.encrypted, envelope.iv, envelope.tag, licenseKey);\n }\n } catch (err) {\n logger.warn('sync: could not decrypt existing payload, starting fresh', { error: String(err) });\n existingPayload = null;\n }\n\n // Capture current local state\n const snapshot = await captureSnapshot();\n const machineId = await getMachineId();\n const machineName = hostname();\n\n const localState: MachineState = {\n machineId,\n machineName,\n updatedAt: new Date().toISOString(),\n snapshot,\n ...(currentBrewfile ? { brewfile: currentBrewfile } : {}),\n };\n\n // Detect conflicts against other machines in the payload\n const otherMachines = existingPayload\n ? Object.values(existingPayload.machines).filter((m) => m.machineId !== machineId)\n : [];\n\n const conflicts = detectConflicts(snapshot, otherMachines, machineId);\n\n // Always write the local machine state to the payload, even when conflicts\n // exist, so that applyConflictResolutions() has a local entry to update.\n // Without this, the iCloud envelope keeps only remote machines, and\n // resolution updates are silently dropped (they require localMachine to exist).\n const basePayload: SyncPayload = existingPayload ?? { machines: {} };\n const mergedPayload = mergePayload(basePayload, localState);\n\n if (conflicts.length > 0) {\n // Persist local state, then surface conflicts so the user can resolve them.\n await writeEnvelope(mergedPayload, licenseKey);\n return {\n success: false,\n conflicts,\n resolvedCount: 0,\n };\n }\n\n const now = await writeEnvelope(mergedPayload, licenseKey);\n\n // Update local sync config\n const existingConfig = await loadSyncConfig();\n await saveSyncConfig({\n enabled: true,\n machineId,\n machineName,\n ...(existingConfig ?? {}),\n lastSync: now,\n });\n\n logger.info('sync: completed successfully', { machineId, machines: Object.keys(mergedPayload.machines).length });\n\n return {\n success: true,\n conflicts: [],\n resolvedCount: 0,\n };\n}\n\n// ── Conflict resolution ──────────────────────────────────────────────────────\n\nexport async function applyConflictResolutions(\n payload: SyncPayload,\n resolutions: Array<{ conflict: SyncConflict; resolution: 'use-local' | 'use-remote' }>,\n localMachineId: string,\n): Promise<void> {\n // Work on a mutable copy\n const updatedPayload: SyncPayload = {\n machines: { ...payload.machines },\n };\n\n for (const { conflict, resolution } of resolutions) {\n if (resolution !== 'use-remote') continue;\n // Re-read latest local machine on every iteration so consecutive resolutions\n // build on top of each other instead of overwriting prior changes.\n const localMachine = updatedPayload.machines[localMachineId];\n if (!localMachine) {\n logger.warn('sync: cannot apply resolution, local machine missing in payload', { localMachineId });\n continue;\n }\n if (conflict.packageType === 'formula') {\n updatedPayload.machines[localMachineId] = {\n ...localMachine,\n snapshot: {\n ...localMachine.snapshot,\n formulae: localMachine.snapshot.formulae.map((f) =>\n f.name === conflict.packageName\n ? { ...f, version: conflict.remoteVersion }\n : f,\n ),\n },\n };\n } else {\n updatedPayload.machines[localMachineId] = {\n ...localMachine,\n snapshot: {\n ...localMachine.snapshot,\n casks: localMachine.snapshot.casks.map((c) =>\n c.name === conflict.packageName\n ? { ...c, version: conflict.remoteVersion }\n : c,\n ),\n },\n };\n }\n }\n\n const licenseKey = await loadLicenseKeyOrThrow();\n await writeEnvelope(updatedPayload, licenseKey);\n logger.info('sync: conflict resolutions applied', { count: resolutions.length });\n}\n","import { createCipheriv, createDecipheriv, randomBytes, scryptSync, hkdfSync } from 'node:crypto';\nimport type { SyncPayload } from './types.js';\n\n// SEG-003: Cross-machine sync encryption.\n// The two constants below are public (compiled into the npm bundle). The\n// per-user secret factor is the Polar license key, which only the user's\n// own machines hold and which Polar issues — so any two of the user's\n// machines derive the same key, but bundle + iCloud snoop is no longer\n// enough to decrypt: the attacker also needs the license key.\n//\n// HKDF-SHA256 over scrypt: the license key is high-entropy by construction\n// (Polar issues UUID-style keys), so the cost-hardening of scrypt isn't\n// what's protecting the key — the secrecy of the license key is. HKDF is\n// also faster, so machines don't pay scrypt's CPU tax on every sync.\nconst ENCRYPTION_SECRET = 'brew-tui-sync-aes256gcm-v1';\nconst HKDF_SALT = 'brew-tui-sync-salt-v1';\n\nconst keyCache = new Map<string, Buffer>();\nlet _legacyKey: Buffer | null = null;\n\nfunction deriveEncryptionKey(licenseKey: string): Buffer {\n const cached = keyCache.get(licenseKey);\n if (cached) return cached;\n const derived = Buffer.from(hkdfSync('sha256', ENCRYPTION_SECRET, HKDF_SALT, licenseKey, 32));\n keyCache.set(licenseKey, derived);\n return derived;\n}\n\n// Legacy key — scrypt(SECRET, SALT), no license-key factor. Used as a\n// decryption fallback for envelopes written by 0.6.2 and earlier.\nfunction deriveLegacyKey(): Buffer {\n if (!_legacyKey) {\n _legacyKey = scryptSync(ENCRYPTION_SECRET, HKDF_SALT, 32, { N: 16384, r: 8, p: 1 });\n }\n return _legacyKey;\n}\n\nexport function encryptPayload(data: SyncPayload, licenseKey: string): { encrypted: string; iv: string; tag: string } {\n const key = deriveEncryptionKey(licenseKey);\n const iv = randomBytes(12); // 96-bit IV for GCM\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n\n const plaintext = JSON.stringify(data);\n const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf-8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n return {\n encrypted: ciphertext.toString('base64'),\n iv: iv.toString('base64'),\n tag: tag.toString('base64'),\n };\n}\n\nexport function decryptPayload(encrypted: string, iv: string, tag: string, licenseKey: string): SyncPayload {\n const ivBuf = Buffer.from(iv, 'base64');\n const tagBuf = Buffer.from(tag, 'base64');\n const ciphertext = Buffer.from(encrypted, 'base64');\n\n // Try the licenseKey-bound key first; fall back to the legacy bundle-only\n // key for envelopes written by 0.6.2 and earlier. Re-encryption happens\n // automatically on the next sync write because writeEnvelope always uses\n // the current key.\n for (const key of [deriveEncryptionKey(licenseKey), deriveLegacyKey()]) {\n try {\n const decipher = createDecipheriv('aes-256-gcm', key, ivBuf);\n decipher.setAuthTag(tagBuf);\n const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return JSON.parse(plaintext.toString('utf-8')) as SyncPayload;\n } catch { /* try next */ }\n }\n throw new Error('Failed to decrypt sync payload');\n}\n","import { readFile, writeFile, rename, mkdir, stat } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { logger } from '../../../utils/logger.js';\nimport type { SyncEnvelope } from '../types.js';\n\nconst ICLOUD_BASE = join(\n homedir(),\n 'Library', 'Mobile Documents', 'com~apple~CloudDocs',\n);\nexport const ICLOUD_SYNC_DIR = join(ICLOUD_BASE, 'BrewTUI');\nexport const ICLOUD_SYNC_PATH = join(ICLOUD_SYNC_DIR, 'sync.json');\n\nexport async function isICloudAvailable(): Promise<boolean> {\n try {\n await stat(ICLOUD_BASE);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidEnvelope(v: unknown): v is SyncEnvelope {\n if (!v || typeof v !== 'object') return false;\n const obj = v as Record<string, unknown>;\n return (\n obj['schemaVersion'] === 1 &&\n typeof obj['encrypted'] === 'string' &&\n typeof obj['iv'] === 'string' &&\n typeof obj['tag'] === 'string' &&\n typeof obj['updatedAt'] === 'string'\n );\n}\n\nexport async function readSyncEnvelope(): Promise<SyncEnvelope | null> {\n try {\n const raw = await readFile(ICLOUD_SYNC_PATH, 'utf-8');\n const parsed: unknown = JSON.parse(raw);\n if (!isValidEnvelope(parsed)) {\n logger.warn('sync: invalid envelope structure in iCloud file');\n return null;\n }\n return parsed;\n } catch (err: unknown) {\n // File does not exist yet — expected on first sync\n if (\n err instanceof Error &&\n (err as NodeJS.ErrnoException).code === 'ENOENT'\n ) {\n return null;\n }\n logger.warn('sync: could not read iCloud envelope', { error: String(err) });\n return null;\n }\n}\n\nexport async function writeSyncEnvelope(envelope: SyncEnvelope): Promise<void> {\n await mkdir(ICLOUD_SYNC_DIR, { recursive: true });\n const tmpPath = ICLOUD_SYNC_PATH + '.tmp';\n await writeFile(tmpPath, JSON.stringify(envelope, null, 2), {\n encoding: 'utf-8',\n mode: 0o600,\n });\n await rename(tmpPath, ICLOUD_SYNC_PATH);\n}\n","import { readFile, writeFile, rename, rm } from 'node:fs/promises';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync, hkdfSync } from 'node:crypto';\nimport { LICENSE_PATH, ensureDataDirs, getMachineId } from '../data-dir.js';\nimport { activateLicense as apiActivate, validateLicense as apiValidate, deactivateLicense as apiDeactivate } from './polar-api.js';\nimport { t } from '../../i18n/index.js';\nimport type { LicenseData, LicenseFile } from './types.js';\n\n// SEG-009: Built-in perennial accounts removed from the bundle.\n// Previously a hardcoded map of customer emails bypassed Polar validation entirely;\n// any user could craft a license.json with one of those emails (the AES key is\n// derivable from the bundle) and gain perennial Pro/Team. Operator accounts now\n// authenticate via real Polar license keys like everyone else. This function is\n// retained as a stable export but always returns null; remove it once no caller\n// references it.\nexport function getBuiltinAccountType(_email: string): 'pro' | 'team' | 'free' | null {\n return null;\n}\n\nconst REVALIDATION_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24h\nconst GRACE_PERIOD_MS = 7 * 24 * 60 * 60 * 1000; // 7 days\n\n// ── Layer 18: Client-side rate limiting on activations ──\nconst ACTIVATION_COOLDOWN_MS = 30_000; // 30 seconds between attempts\nconst MAX_ATTEMPTS = 5;\nconst LOCKOUT_MS = 15 * 60 * 1000; // 15 min lockout after max attempts\n\ninterface ActivationTracker {\n attempts: number;\n lastAttempt: number;\n lockedUntil: number;\n}\n\n// Note: rate limit state is in-memory only; resets on process restart\nconst tracker: ActivationTracker = {\n attempts: 0,\n lastAttempt: 0,\n lockedUntil: 0,\n};\n\nfunction checkRateLimit(): void {\n const now = Date.now();\n\n // Check lockout\n if (now < tracker.lockedUntil) {\n const remaining = Math.ceil((tracker.lockedUntil - now) / 60000);\n throw new Error(t('cli_rateLimited', { minutes: remaining }));\n }\n\n // Check cooldown\n if (now - tracker.lastAttempt < ACTIVATION_COOLDOWN_MS) {\n throw new Error(t('cli_cooldown'));\n }\n}\n\nfunction recordAttempt(success: boolean): void {\n const now = Date.now();\n tracker.lastAttempt = now;\n\n if (success) {\n tracker.attempts = 0;\n return;\n }\n\n tracker.attempts++;\n if (tracker.attempts >= MAX_ATTEMPTS) {\n tracker.lockedUntil = now + LOCKOUT_MS;\n tracker.attempts = 0;\n }\n}\n\n// SECURITY (SEG-002): the bundle-only constants below USED to be the entire\n// derivation input — anyone with the npm bundle could decrypt any user's\n// license.json. Now the per-user machineId is mixed into the HKDF info, so\n// the bundle alone is no longer sufficient: an attacker also needs the\n// target's ~/.brew-tui/machine-id. The two constants stay published; what's\n// secret is the user's local machineId, which never leaves the machine.\n//\n// HKDF-SHA256 was chosen over scrypt because Swift's CryptoKit (used by\n// BrewBar to read the same license.json) ships HKDF natively but not scrypt.\n// machineId is a UUIDv4 with 122 bits of entropy, so the cost-hardening of\n// scrypt is not what's protecting the key — the secrecy of the machineId is.\nconst ENCRYPTION_SECRET = 'brew-tui-license-aes256gcm-v1';\nconst HKDF_SALT = 'brew-tui-salt-v1';\n\nlet _derivedKey: Buffer | null = null;\nlet _legacyKey: Buffer | null = null;\nlet _decryptedWithLegacyKey = false;\n\nasync function deriveEncryptionKey(): Promise<Buffer> {\n if (_derivedKey) return _derivedKey;\n const machineId = await getMachineId();\n // HKDF: ikm = SECRET, salt = HKDF_SALT, info = machineId, len = 32\n const derived = hkdfSync('sha256', ENCRYPTION_SECRET, HKDF_SALT, machineId, 32);\n _derivedKey = Buffer.from(derived);\n return _derivedKey;\n}\n\n// Legacy key — scrypt(SECRET, SALT) with no machineId. Pre-existing\n// license.json files written by 0.6.2 and earlier are ciphered with this.\n// decryptLicenseData falls back to it; the next saveLicense re-ciphers\n// using the HKDF key. Drop once the fallback stops being hit in the wild.\nfunction deriveLegacyKey(): Buffer {\n if (!_legacyKey) _legacyKey = scryptSync(ENCRYPTION_SECRET, HKDF_SALT, 32);\n return _legacyKey;\n}\n\nasync function encryptLicenseData(data: LicenseData): Promise<{ encrypted: string; iv: string; tag: string }> {\n const key = await deriveEncryptionKey();\n const iv = randomBytes(12); // 96-bit IV for GCM\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n\n const plaintext = JSON.stringify(data);\n const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf-8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n return {\n encrypted: ciphertext.toString('base64'),\n iv: iv.toString('base64'),\n tag: tag.toString('base64'),\n };\n}\n\nasync function decryptLicenseData(encrypted: string, iv: string, tag: string): Promise<LicenseData> {\n const ivBuf = Buffer.from(iv, 'base64');\n const tagBuf = Buffer.from(tag, 'base64');\n const ciphertext = Buffer.from(encrypted, 'base64');\n\n // Try the current (machine-bound) key first; fall back to the legacy\n // (bundle-only) key for upgrade compatibility.\n const candidates: Array<[Buffer, boolean]> = [\n [await deriveEncryptionKey(), false],\n [deriveLegacyKey(), true],\n ];\n let lastErr: unknown;\n for (const [key, isLegacy] of candidates) {\n try {\n const decipher = createDecipheriv('aes-256-gcm', key, ivBuf);\n decipher.setAuthTag(tagBuf);\n const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n _decryptedWithLegacyKey = isLegacy;\n return JSON.parse(plaintext.toString('utf-8')) as LicenseData;\n } catch (err) { lastErr = err; }\n }\n throw lastErr instanceof Error ? lastErr : new Error('Failed to decrypt license');\n}\n\n// BK-003: Type guard for license data format\nfunction isLicenseFile(obj: unknown): obj is LicenseFile {\n return typeof obj === 'object' && obj !== null && (obj as Record<string, unknown>).version === 1;\n}\n\nfunction isEncryptedLicenseFile(obj: unknown): obj is LicenseFile & { encrypted: string; iv: string; tag: string } {\n if (!isLicenseFile(obj)) return false;\n const record = obj as unknown as Record<string, unknown>;\n return typeof record.encrypted === 'string'\n && typeof record.iv === 'string'\n && typeof record.tag === 'string';\n}\n\nexport async function loadLicense(): Promise<LicenseData | null> {\n try {\n const raw = await readFile(LICENSE_PATH, 'utf-8');\n const parsed: unknown = JSON.parse(raw);\n\n // BK-003: Validate parsed data\n if (!isLicenseFile(parsed)) {\n throw new Error('Invalid license data format');\n }\n\n const file = parsed as LicenseFile;\n\n if (file.version !== 1) {\n // Future: add migration logic here\n throw new Error('Unsupported data version');\n }\n\n // New encrypted format\n if (isEncryptedLicenseFile(file)) {\n const data = await decryptLicenseData(file.encrypted!, file.iv!, file.tag!);\n\n // SEG-002: Check machine ID if stored in the envelope.\n // getMachineId() now always resolves a value — if the user's machine-id\n // file was wiped, a new UUID is created and this check rejects the\n // license, prompting reactivation. Same behaviour the polar-api flow\n // already had on save.\n const fileRecord = file as unknown as Record<string, unknown>;\n if (fileRecord.machineId) {\n const currentMachineId = await getMachineId();\n if (fileRecord.machineId !== currentMachineId) {\n throw new Error('License was activated on a different machine');\n }\n }\n\n // If we fell back to the legacy bundle-only key, re-cipher with the\n // current machine-bound key so future reads use the strong path.\n if (_decryptedWithLegacyKey) {\n _decryptedWithLegacyKey = false;\n try { await saveLicense(data); } catch { /* best effort */ }\n }\n\n return data;\n }\n\n // Legacy unencrypted format — migrate to encrypted on read\n if (file.license) {\n const data = file.license;\n // Re-save in encrypted format\n await saveLicense(data);\n return data;\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\nexport async function saveLicense(data: LicenseData): Promise<void> {\n await ensureDataDirs();\n const { encrypted, iv, tag } = await encryptLicenseData(data);\n // SEG-002: Include machineId in the envelope for portability detection\n const machineId = await getMachineId();\n const file: Record<string, unknown> = { version: 1, encrypted, iv, tag, machineId };\n const tmpPath = LICENSE_PATH + '.tmp';\n await writeFile(tmpPath, JSON.stringify(file, null, 2), { encoding: 'utf-8', mode: 0o600 });\n await rename(tmpPath, LICENSE_PATH);\n}\n\nexport async function clearLicense(): Promise<void> {\n try {\n await rm(LICENSE_PATH);\n } catch { /* file may not exist */ }\n}\n\nexport function isExpired(license: LicenseData): boolean {\n if (!license.expiresAt) return false;\n const expiry = new Date(license.expiresAt).getTime();\n // Fail closed on corrupted/unparseable dates: NaN comparisons are always\n // false, so the previous version treated a garbage expiresAt as \"never\n // expires\", which is exploitable.\n if (isNaN(expiry)) return true;\n return expiry < Date.now();\n}\n\nexport function needsRevalidation(license: LicenseData): boolean {\n const lastValidated = new Date(license.lastValidatedAt).getTime();\n if (isNaN(lastValidated)) return true; // corrupted date → force revalidation\n return Date.now() - lastValidated > REVALIDATION_INTERVAL_MS;\n}\n\nexport function isWithinGracePeriod(license: LicenseData): boolean {\n const lastValidated = new Date(license.lastValidatedAt).getTime();\n if (isNaN(lastValidated)) return false; // corrupted date → no grace\n return Date.now() - lastValidated < GRACE_PERIOD_MS;\n}\n\n// ── Layer 15: Gradual degradation after extended offline ──\n\nexport type DegradationLevel = 'none' | 'warning' | 'limited' | 'expired';\nexport type RevalidationResult = 'valid' | 'grace' | 'expired';\n\n/**\n * Returns the degradation level based on time since last server validation.\n * - 0-7 days: none (full access)\n * - 7-14 days: warning (shows a notice but still works)\n * - 14-30 days: limited (some features disabled)\n * - 30+ days: expired (all Pro features disabled)\n */\nexport function getDegradationLevel(license: LicenseData): DegradationLevel {\n const lastValidated = new Date(license.lastValidatedAt).getTime();\n if (isNaN(lastValidated)) return 'expired'; // corrupted date → deny access\n const elapsed = Date.now() - lastValidated;\n if (elapsed < 0) return 'none'; // clock skew: future timestamp → treat as fresh\n const days = elapsed / (24 * 60 * 60 * 1000);\n\n if (days <= 7) return 'none';\n if (days <= 14) return 'warning';\n if (days <= 30) return 'limited';\n return 'expired';\n}\n\n// Layer 10: License key format validation\nfunction validateLicenseKey(key: string): void {\n // Polar keys are UUID-like: 8-4-4-4-12 hex chars or similar\n // Reject obviously invalid keys to avoid unnecessary API calls\n if (key.length < 10 || key.length > 100) {\n throw new Error('Invalid license key format');\n }\n // Only allow alphanumeric, hyphens, underscores\n if (!/^[\\w-]+$/.test(key)) {\n throw new Error('Invalid license key format');\n }\n}\n\n// Polar license-key benefits use distinct prefixes per tier:\n// Pro Monthly/Yearly → \"BTUI-...\"\n// Team Monthly/Yearly → \"BTUI-T-...\"\n// We detect the tier from the prefix instead of looking up the productId,\n// because Polar's customer-portal license endpoints don't echo product info\n// in the activation response.\nfunction detectPlan(key: string): 'pro' | 'team' {\n const upper = key.toUpperCase();\n return upper.startsWith('BTUI-T-') || upper.startsWith('BTUI-T_') ? 'team' : 'pro';\n}\n\nexport async function activate(key: string): Promise<LicenseData> {\n validateLicenseKey(key);\n checkRateLimit();\n\n let success = false;\n try {\n const res = await apiActivate(key);\n\n if (!res.activated) {\n throw new Error(res.error ?? 'Activation failed');\n }\n\n const license: LicenseData = {\n key,\n instanceId: res.instance.id,\n status: 'active',\n customerEmail: res.meta.customer_email,\n customerName: res.meta.customer_name,\n plan: detectPlan(key),\n activatedAt: new Date().toISOString(),\n expiresAt: res.license_key.expires_at,\n lastValidatedAt: new Date().toISOString(),\n };\n\n await saveLicense(license);\n success = true;\n return license;\n } finally {\n recordAttempt(success);\n }\n}\n\n/**\n * Revalidate the license against the server.\n * This also serves as Layer 19 (telemetry): each validation call\n * allows Polar to track activation count, last-seen timestamp,\n * and detect if the activation limit is exceeded (license sharing).\n */\n// EP-006: Detect if an error is a network error vs validation/contract error\nfunction isNetworkError(err: unknown): boolean {\n const msg = err instanceof Error ? err.message : String(err);\n return /fetch failed|ECONNREFUSED|ENOTFOUND|ETIMEDOUT|network|timeout|abort/i.test(msg);\n}\n\nexport async function revalidate(license: LicenseData): Promise<RevalidationResult> {\n try {\n const res = await apiValidate(license.key, license.instanceId);\n\n if (res.valid) {\n const updated: LicenseData = {\n ...license,\n lastValidatedAt: new Date().toISOString(),\n status: 'active',\n expiresAt: res.license_key.expires_at,\n };\n await saveLicense(updated);\n return 'valid';\n }\n\n await saveLicense({ ...license, status: 'expired' });\n return 'expired';\n } catch (err) {\n // EP-006: Network errors trigger grace period; validation/contract errors mean expired\n if (isNetworkError(err)) {\n return isWithinGracePeriod(license) ? 'grace' : 'expired';\n }\n // Unexpected response or contract violation — treat as expired\n await saveLicense({ ...license, status: 'expired' });\n return 'expired';\n }\n}\n\nexport async function deactivate(license: LicenseData): Promise<{ remoteSuccess: boolean }> {\n let remoteSuccess = false;\n for (let attempt = 0; attempt < 3; attempt++) {\n try {\n await apiDeactivate(license.key, license.instanceId);\n remoteSuccess = true;\n break;\n } catch {\n if (attempt < 2) await new Promise(r => setTimeout(r, 1000));\n }\n }\n await clearLicense();\n return { remoteSuccess };\n}\n","import type { PolarActivateResponse, PolarValidateResponse } from './types.js';\nimport { fetchWithRetry } from '../fetch-timeout.js';\nimport { getMachineId } from '../data-dir.js';\n\nconst BASE_URL = 'https://api.polar.sh/v1/customer-portal/license-keys';\n\n// ── GOV-004: Public organization ID (not a secret) ──\n// This is the public Polar organization identifier used for license key operations.\n// Found at: polar.sh/dashboard -> Settings -> General\nexport const POLAR_ORGANIZATION_ID = 'b8f245c0-d116-4457-92fb-1bda47139f82';\n\n// Polar product IDs (public, not secret) — useful for analytics, support, and\n// future server-side validation that wants to confirm what the customer bought.\nexport const POLAR_PRODUCT_IDS = {\n proMonthly: 'b925b882-464c-40c1-9ffd-b088ab31d9a3',\n proYearly: '8f97bb81-b950-4bc3-97c5-8133dd817d0b',\n teamMonthly: '7cf3fcb2-560d-4fbb-9936-15efac511b23',\n teamYearly: 'd096914d-902d-47b0-8d62-5c7e6fc4e087',\n} as const;\n\n// Public checkout URLs surfaced from the landing page and the CLI upgrade prompt.\n// Team links carry ?quantity=3 because Polar has no native min-seats enforcement\n// and the Team tier is sold from 3 seats up.\nexport const POLAR_CHECKOUT_URLS = {\n proMonthly: 'https://buy.polar.sh/polar_cl_QW1ZJ9887bU74drGr7JfujQfm3RKYnn1fuvc53DqD6D',\n proYearly: 'https://buy.polar.sh/polar_cl_yQsiUeDelyyEQznbWffD1j77JAyP24ra7iEVQ22PA4h',\n teamMonthly: 'https://buy.polar.sh/polar_cl_CO6xqSzKgFiQJwXnhZYGqisOP04Wspi0KKZSn38NjFZ?quantity=3',\n teamYearly: 'https://buy.polar.sh/polar_cl_BZowqmtaKwWEkRJNtBcashWg7oZOH6OhnnsJ204opNA?quantity=3',\n} as const;\n\n// Layer 11: API URL validation\nfunction validateApiUrl(url: string): void {\n const parsed = new URL(url);\n if (parsed.protocol !== 'https:') {\n throw new Error('HTTPS required for license API');\n }\n if (!parsed.hostname.endsWith('polar.sh')) {\n throw new Error('Invalid API host');\n }\n}\n\n// Raw Polar response shapes\ninterface PolarActivation {\n id: string; // activation_id\n license_key: {\n status: string;\n expires_at: string | null;\n };\n}\n\ninterface PolarValidated {\n id: string;\n status: string; // 'granted' | 'revoked' | 'disabled'\n expires_at: string | null;\n customer: {\n email: string | null;\n name: string | null;\n };\n activation: { id: string } | null;\n}\n\nasync function post<T>(endpoint: string, body: Record<string, unknown>, expectEmpty = false): Promise<T> {\n const url = `${BASE_URL}/${endpoint}`;\n validateApiUrl(url);\n\n const res = await fetchWithRetry(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n }, 15_000);\n\n if (!res.ok) {\n let message = `Request failed with status ${res.status}`;\n try {\n const errBody = await res.json() as { detail?: string; error?: string; message?: string };\n if (typeof errBody.detail === 'string') message = errBody.detail;\n else if (typeof errBody.error === 'string') message = errBody.error;\n else if (typeof errBody.message === 'string') message = errBody.message;\n } catch {\n // non-JSON error body — use generic message above\n }\n throw new Error(message);\n }\n\n if (expectEmpty || res.status === 204) return undefined as T;\n return res.json() as Promise<T>;\n}\n\nexport async function activateLicense(key: string): Promise<PolarActivateResponse> {\n const machineId = await getMachineId();\n\n const activation = await post<PolarActivation>('activate', {\n key,\n organization_id: POLAR_ORGANIZATION_ID,\n label: machineId, // SEG-004: Use machine UUID instead of hostname\n });\n\n // EP-001: Runtime validation of activation response\n if (!activation || typeof activation.id !== 'string' || !activation.license_key) {\n throw new Error('Invalid activation response: missing required fields');\n }\n\n // Polar's activate response doesn't include customer info — fetch it via validate\n let customerEmail = '';\n let customerName = '';\n try {\n const validated = await post<PolarValidated>('validate', {\n key,\n organization_id: POLAR_ORGANIZATION_ID,\n activation_id: activation.id,\n });\n customerEmail = validated.customer?.email ?? '';\n customerName = validated.customer?.name ?? '';\n } catch {\n // customer info is non-critical — activation still succeeds\n }\n\n return {\n activated: true,\n error: null,\n instance: { id: activation.id },\n license_key: {\n id: 0,\n status: activation.license_key.status,\n key,\n activation_limit: 0,\n activations_count: 0,\n expires_at: activation.license_key.expires_at,\n },\n meta: { customer_email: customerEmail, customer_name: customerName },\n };\n}\n\nexport async function validateLicense(key: string, instanceId: string): Promise<PolarValidateResponse> {\n const res = await post<PolarValidated>('validate', {\n key,\n organization_id: POLAR_ORGANIZATION_ID,\n activation_id: instanceId,\n });\n\n // EP-002: Runtime validation of validate response\n if (!res || typeof res.id !== 'string' || typeof res.status !== 'string' || !res.customer) {\n throw new Error('Invalid validation response: missing required fields');\n }\n\n const notExpired = res.expires_at === null || new Date(res.expires_at) > new Date();\n const valid = res.status === 'granted' && notExpired;\n\n return {\n valid,\n error: valid ? null : `License ${res.status}`,\n license_key: {\n id: 0,\n status: res.status,\n key,\n expires_at: res.expires_at,\n },\n instance: { id: instanceId },\n };\n}\n\nexport async function deactivateLicense(key: string, instanceId: string): Promise<void> {\n await post<void>(\n 'deactivate',\n { key, organization_id: POLAR_ORGANIZATION_ID, activation_id: instanceId },\n true,\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA,SAAS,YAAAA,WAAU,aAAAC,YAAW,UAAAC,eAAc;AAC5C,SAAS,QAAAC,aAAY;AACrB,SAAS,gBAAgB;;;ACFzB,SAAS,gBAAgB,kBAAkB,aAAa,YAAY,gBAAgB;AAcpF,IAAM,oBAAoB;AAC1B,IAAM,YAAY;AAElB,IAAM,WAAW,oBAAI,IAAoB;AACzC,IAAI,aAA4B;AAEhC,SAAS,oBAAoB,YAA4B;AACvD,QAAM,SAAS,SAAS,IAAI,UAAU;AACtC,MAAI,OAAQ,QAAO;AACnB,QAAM,UAAU,OAAO,KAAK,SAAS,UAAU,mBAAmB,WAAW,YAAY,EAAE,CAAC;AAC5F,WAAS,IAAI,YAAY,OAAO;AAChC,SAAO;AACT;AAIA,SAAS,kBAA0B;AACjC,MAAI,CAAC,YAAY;AACf,iBAAa,WAAW,mBAAmB,WAAW,IAAI,EAAE,GAAG,OAAO,GAAG,GAAG,GAAG,EAAE,CAAC;AAAA,EACpF;AACA,SAAO;AACT;AAEO,SAAS,eAAe,MAAmB,YAAoE;AACpH,QAAM,MAAM,oBAAoB,UAAU;AAC1C,QAAM,KAAK,YAAY,EAAE;AACzB,QAAM,SAAS,eAAe,eAAe,KAAK,EAAE;AAEpD,QAAM,YAAY,KAAK,UAAU,IAAI;AACrC,QAAM,aAAa,OAAO,OAAO,CAAC,OAAO,OAAO,WAAW,OAAO,GAAG,OAAO,MAAM,CAAC,CAAC;AACpF,QAAM,MAAM,OAAO,WAAW;AAE9B,SAAO;AAAA,IACL,WAAW,WAAW,SAAS,QAAQ;AAAA,IACvC,IAAI,GAAG,SAAS,QAAQ;AAAA,IACxB,KAAK,IAAI,SAAS,QAAQ;AAAA,EAC5B;AACF;AAEO,SAAS,eAAe,WAAmB,IAAY,KAAa,YAAiC;AAC1G,QAAM,QAAQ,OAAO,KAAK,IAAI,QAAQ;AACtC,QAAM,SAAS,OAAO,KAAK,KAAK,QAAQ;AACxC,QAAM,aAAa,OAAO,KAAK,WAAW,QAAQ;AAMlD,aAAW,OAAO,CAAC,oBAAoB,UAAU,GAAG,gBAAgB,CAAC,GAAG;AACtE,QAAI;AACF,YAAM,WAAW,iBAAiB,eAAe,KAAK,KAAK;AAC3D,eAAS,WAAW,MAAM;AAC1B,YAAM,YAAY,OAAO,OAAO,CAAC,SAAS,OAAO,UAAU,GAAG,SAAS,MAAM,CAAC,CAAC;AAC/E,aAAO,KAAK,MAAM,UAAU,SAAS,OAAO,CAAC;AAAA,IAC/C,QAAQ;AAAA,IAAiB;AAAA,EAC3B;AACA,QAAM,IAAI,MAAM,gCAAgC;AAClD;;;ACvEA,SAAS,UAAU,WAAW,QAAQ,OAAO,YAAY;AACzD,SAAS,eAAe;AACxB,SAAS,YAAY;AAIrB,IAAM,cAAc;AAAA,EAClB,QAAQ;AAAA,EACR;AAAA,EAAW;AAAA,EAAoB;AACjC;AACO,IAAM,kBAAkB,KAAK,aAAa,SAAS;AACnD,IAAM,mBAAmB,KAAK,iBAAiB,WAAW;AAEjE,eAAsB,oBAAsC;AAC1D,MAAI;AACF,UAAM,KAAK,WAAW;AACtB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,gBAAgB,GAA+B;AACtD,MAAI,CAAC,KAAK,OAAO,MAAM,SAAU,QAAO;AACxC,QAAM,MAAM;AACZ,SACE,IAAI,eAAe,MAAM,KACzB,OAAO,IAAI,WAAW,MAAM,YAC5B,OAAO,IAAI,IAAI,MAAM,YACrB,OAAO,IAAI,KAAK,MAAM,YACtB,OAAO,IAAI,WAAW,MAAM;AAEhC;AAEA,eAAsB,mBAAiD;AACrE,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,kBAAkB,OAAO;AACpD,UAAM,SAAkB,KAAK,MAAM,GAAG;AACtC,QAAI,CAAC,gBAAgB,MAAM,GAAG;AAC5B,aAAO,KAAK,iDAAiD;AAC7D,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,SAAS,KAAc;AAErB,QACE,eAAe,SACd,IAA8B,SAAS,UACxC;AACA,aAAO;AAAA,IACT;AACA,WAAO,KAAK,wCAAwC,EAAE,OAAO,OAAO,GAAG,EAAE,CAAC;AAC1E,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,kBAAkB,UAAuC;AAC7E,QAAM,MAAM,iBAAiB,EAAE,WAAW,KAAK,CAAC;AAChD,QAAM,UAAU,mBAAmB;AACnC,QAAM,UAAU,SAAS,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG;AAAA,IAC1D,UAAU;AAAA,IACV,MAAM;AAAA,EACR,CAAC;AACD,QAAM,OAAO,SAAS,gBAAgB;AACxC;;;AChEA,SAAS,YAAAC,WAAU,aAAAC,YAAW,UAAAC,SAAQ,UAAU;AAChD,SAAS,kBAAAC,iBAAgB,oBAAAC,mBAAkB,eAAAC,cAAa,cAAAC,aAAY,YAAAC,iBAAgB;;;ACGpF,IAAM,WAAW;AAKV,IAAM,wBAAwB;AAsBrC,SAAS,eAAe,KAAmB;AACzC,QAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,MAAI,OAAO,aAAa,UAAU;AAChC,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AACA,MAAI,CAAC,OAAO,SAAS,SAAS,UAAU,GAAG;AACzC,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACpC;AACF;AAsBA,eAAe,KAAQ,UAAkB,MAA+B,cAAc,OAAmB;AACvG,QAAM,MAAM,GAAG,QAAQ,IAAI,QAAQ;AACnC,iBAAe,GAAG;AAElB,QAAM,MAAM,MAAM,eAAe,KAAK;AAAA,IACpC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,GAAG,IAAM;AAET,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,UAAU,8BAA8B,IAAI,MAAM;AACtD,QAAI;AACF,YAAM,UAAU,MAAM,IAAI,KAAK;AAC/B,UAAI,OAAO,QAAQ,WAAW,SAAU,WAAU,QAAQ;AAAA,eACjD,OAAO,QAAQ,UAAU,SAAU,WAAU,QAAQ;AAAA,eACrD,OAAO,QAAQ,YAAY,SAAU,WAAU,QAAQ;AAAA,IAClE,QAAQ;AAAA,IAER;AACA,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AAEA,MAAI,eAAe,IAAI,WAAW,IAAK,QAAO;AAC9C,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,gBAAgB,KAA6C;AACjF,QAAM,YAAY,MAAM,aAAa;AAErC,QAAM,aAAa,MAAM,KAAsB,YAAY;AAAA,IACzD;AAAA,IACA,iBAAiB;AAAA,IACjB,OAAO;AAAA;AAAA,EACT,CAAC;AAGD,MAAI,CAAC,cAAc,OAAO,WAAW,OAAO,YAAY,CAAC,WAAW,aAAa;AAC/E,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AAGA,MAAI,gBAAgB;AACpB,MAAI,eAAe;AACnB,MAAI;AACF,UAAM,YAAY,MAAM,KAAqB,YAAY;AAAA,MACvD;AAAA,MACA,iBAAiB;AAAA,MACjB,eAAe,WAAW;AAAA,IAC5B,CAAC;AACD,oBAAgB,UAAU,UAAU,SAAS;AAC7C,mBAAe,UAAU,UAAU,QAAQ;AAAA,EAC7C,QAAQ;AAAA,EAER;AAEA,SAAO;AAAA,IACL,WAAW;AAAA,IACX,OAAO;AAAA,IACP,UAAU,EAAE,IAAI,WAAW,GAAG;AAAA,IAC9B,aAAa;AAAA,MACX,IAAI;AAAA,MACJ,QAAQ,WAAW,YAAY;AAAA,MAC/B;AAAA,MACA,kBAAkB;AAAA,MAClB,mBAAmB;AAAA,MACnB,YAAY,WAAW,YAAY;AAAA,IACrC;AAAA,IACA,MAAM,EAAE,gBAAgB,eAAe,eAAe,aAAa;AAAA,EACrE;AACF;AAEA,eAAsB,gBAAgB,KAAa,YAAoD;AACrG,QAAM,MAAM,MAAM,KAAqB,YAAY;AAAA,IACjD;AAAA,IACA,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB,CAAC;AAGD,MAAI,CAAC,OAAO,OAAO,IAAI,OAAO,YAAY,OAAO,IAAI,WAAW,YAAY,CAAC,IAAI,UAAU;AACzF,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AAEA,QAAM,aAAa,IAAI,eAAe,QAAQ,IAAI,KAAK,IAAI,UAAU,IAAI,oBAAI,KAAK;AAClF,QAAM,QAAQ,IAAI,WAAW,aAAa;AAE1C,SAAO;AAAA,IACL;AAAA,IACA,OAAO,QAAQ,OAAO,WAAW,IAAI,MAAM;AAAA,IAC3C,aAAa;AAAA,MACX,IAAI;AAAA,MACJ,QAAQ,IAAI;AAAA,MACZ;AAAA,MACA,YAAY,IAAI;AAAA,IAClB;AAAA,IACA,UAAU,EAAE,IAAI,WAAW;AAAA,EAC7B;AACF;AAEA,eAAsB,kBAAkB,KAAa,YAAmC;AACtF,QAAM;AAAA,IACJ;AAAA,IACA,EAAE,KAAK,iBAAiB,uBAAuB,eAAe,WAAW;AAAA,IACzE;AAAA,EACF;AACF;;;ADrJA,IAAM,2BAA2B,KAAK,KAAK,KAAK;AAChD,IAAM,kBAAkB,IAAI,KAAK,KAAK,KAAK;AAG3C,IAAM,yBAAyB;AAC/B,IAAM,eAAe;AACrB,IAAM,aAAa,KAAK,KAAK;AAS7B,IAAM,UAA6B;AAAA,EACjC,UAAU;AAAA,EACV,aAAa;AAAA,EACb,aAAa;AACf;AAEA,SAAS,iBAAuB;AAC9B,QAAM,MAAM,KAAK,IAAI;AAGrB,MAAI,MAAM,QAAQ,aAAa;AAC7B,UAAM,YAAY,KAAK,MAAM,QAAQ,cAAc,OAAO,GAAK;AAC/D,UAAM,IAAI,MAAM,EAAE,mBAAmB,EAAE,SAAS,UAAU,CAAC,CAAC;AAAA,EAC9D;AAGA,MAAI,MAAM,QAAQ,cAAc,wBAAwB;AACtD,UAAM,IAAI,MAAM,EAAE,cAAc,CAAC;AAAA,EACnC;AACF;AAEA,SAAS,cAAc,SAAwB;AAC7C,QAAM,MAAM,KAAK,IAAI;AACrB,UAAQ,cAAc;AAEtB,MAAI,SAAS;AACX,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,UAAQ;AACR,MAAI,QAAQ,YAAY,cAAc;AACpC,YAAQ,cAAc,MAAM;AAC5B,YAAQ,WAAW;AAAA,EACrB;AACF;AAaA,IAAMC,qBAAoB;AAC1B,IAAMC,aAAY;AAElB,IAAI,cAA6B;AACjC,IAAIC,cAA4B;AAChC,IAAI,0BAA0B;AAE9B,eAAeC,uBAAuC;AACpD,MAAI,YAAa,QAAO;AACxB,QAAM,YAAY,MAAM,aAAa;AAErC,QAAM,UAAUC,UAAS,UAAUJ,oBAAmBC,YAAW,WAAW,EAAE;AAC9E,gBAAc,OAAO,KAAK,OAAO;AACjC,SAAO;AACT;AAMA,SAASI,mBAA0B;AACjC,MAAI,CAACH,YAAY,CAAAA,cAAaI,YAAWN,oBAAmBC,YAAW,EAAE;AACzE,SAAOC;AACT;AAEA,eAAe,mBAAmB,MAA4E;AAC5G,QAAM,MAAM,MAAMC,qBAAoB;AACtC,QAAM,KAAKI,aAAY,EAAE;AACzB,QAAM,SAASC,gBAAe,eAAe,KAAK,EAAE;AAEpD,QAAM,YAAY,KAAK,UAAU,IAAI;AACrC,QAAM,aAAa,OAAO,OAAO,CAAC,OAAO,OAAO,WAAW,OAAO,GAAG,OAAO,MAAM,CAAC,CAAC;AACpF,QAAM,MAAM,OAAO,WAAW;AAE9B,SAAO;AAAA,IACL,WAAW,WAAW,SAAS,QAAQ;AAAA,IACvC,IAAI,GAAG,SAAS,QAAQ;AAAA,IACxB,KAAK,IAAI,SAAS,QAAQ;AAAA,EAC5B;AACF;AAEA,eAAe,mBAAmB,WAAmB,IAAY,KAAmC;AAClG,QAAM,QAAQ,OAAO,KAAK,IAAI,QAAQ;AACtC,QAAM,SAAS,OAAO,KAAK,KAAK,QAAQ;AACxC,QAAM,aAAa,OAAO,KAAK,WAAW,QAAQ;AAIlD,QAAM,aAAuC;AAAA,IAC3C,CAAC,MAAML,qBAAoB,GAAG,KAAK;AAAA,IACnC,CAACE,iBAAgB,GAAG,IAAI;AAAA,EAC1B;AACA,MAAI;AACJ,aAAW,CAAC,KAAK,QAAQ,KAAK,YAAY;AACxC,QAAI;AACF,YAAM,WAAWI,kBAAiB,eAAe,KAAK,KAAK;AAC3D,eAAS,WAAW,MAAM;AAC1B,YAAM,YAAY,OAAO,OAAO,CAAC,SAAS,OAAO,UAAU,GAAG,SAAS,MAAM,CAAC,CAAC;AAC/E,gCAA0B;AAC1B,aAAO,KAAK,MAAM,UAAU,SAAS,OAAO,CAAC;AAAA,IAC/C,SAAS,KAAK;AAAE,gBAAU;AAAA,IAAK;AAAA,EACjC;AACA,QAAM,mBAAmB,QAAQ,UAAU,IAAI,MAAM,2BAA2B;AAClF;AAGA,SAAS,cAAc,KAAkC;AACvD,SAAO,OAAO,QAAQ,YAAY,QAAQ,QAAS,IAAgC,YAAY;AACjG;AAEA,SAAS,uBAAuB,KAAmF;AACjH,MAAI,CAAC,cAAc,GAAG,EAAG,QAAO;AAChC,QAAM,SAAS;AACf,SAAO,OAAO,OAAO,cAAc,YAC9B,OAAO,OAAO,OAAO,YACrB,OAAO,OAAO,QAAQ;AAC7B;AAEA,eAAsB,cAA2C;AAC/D,MAAI;AACF,UAAM,MAAM,MAAMC,UAAS,cAAc,OAAO;AAChD,UAAM,SAAkB,KAAK,MAAM,GAAG;AAGtC,QAAI,CAAC,cAAc,MAAM,GAAG;AAC1B,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAEA,UAAM,OAAO;AAEb,QAAI,KAAK,YAAY,GAAG;AAEtB,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAGA,QAAI,uBAAuB,IAAI,GAAG;AAChC,YAAM,OAAO,MAAM,mBAAmB,KAAK,WAAY,KAAK,IAAK,KAAK,GAAI;AAO1E,YAAM,aAAa;AACnB,UAAI,WAAW,WAAW;AACxB,cAAM,mBAAmB,MAAM,aAAa;AAC5C,YAAI,WAAW,cAAc,kBAAkB;AAC7C,gBAAM,IAAI,MAAM,8CAA8C;AAAA,QAChE;AAAA,MACF;AAIA,UAAI,yBAAyB;AAC3B,kCAA0B;AAC1B,YAAI;AAAE,gBAAM,YAAY,IAAI;AAAA,QAAG,QAAQ;AAAA,QAAoB;AAAA,MAC7D;AAEA,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,SAAS;AAChB,YAAM,OAAO,KAAK;AAElB,YAAM,YAAY,IAAI;AACtB,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,YAAY,MAAkC;AAClE,QAAM,eAAe;AACrB,QAAM,EAAE,WAAW,IAAI,IAAI,IAAI,MAAM,mBAAmB,IAAI;AAE5D,QAAM,YAAY,MAAM,aAAa;AACrC,QAAM,OAAgC,EAAE,SAAS,GAAG,WAAW,IAAI,KAAK,UAAU;AAClF,QAAM,UAAU,eAAe;AAC/B,QAAMC,WAAU,SAAS,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,EAAE,UAAU,SAAS,MAAM,IAAM,CAAC;AAC1F,QAAMC,QAAO,SAAS,YAAY;AACpC;AAEA,eAAsB,eAA8B;AAClD,MAAI;AACF,UAAM,GAAG,YAAY;AAAA,EACvB,QAAQ;AAAA,EAA2B;AACrC;AAEO,SAAS,UAAU,SAA+B;AACvD,MAAI,CAAC,QAAQ,UAAW,QAAO;AAC/B,QAAM,SAAS,IAAI,KAAK,QAAQ,SAAS,EAAE,QAAQ;AAInD,MAAI,MAAM,MAAM,EAAG,QAAO;AAC1B,SAAO,SAAS,KAAK,IAAI;AAC3B;AAEO,SAAS,kBAAkB,SAA+B;AAC/D,QAAM,gBAAgB,IAAI,KAAK,QAAQ,eAAe,EAAE,QAAQ;AAChE,MAAI,MAAM,aAAa,EAAG,QAAO;AACjC,SAAO,KAAK,IAAI,IAAI,gBAAgB;AACtC;AAEO,SAAS,oBAAoB,SAA+B;AACjE,QAAM,gBAAgB,IAAI,KAAK,QAAQ,eAAe,EAAE,QAAQ;AAChE,MAAI,MAAM,aAAa,EAAG,QAAO;AACjC,SAAO,KAAK,IAAI,IAAI,gBAAgB;AACtC;AAcO,SAAS,oBAAoB,SAAwC;AAC1E,QAAM,gBAAgB,IAAI,KAAK,QAAQ,eAAe,EAAE,QAAQ;AAChE,MAAI,MAAM,aAAa,EAAG,QAAO;AACjC,QAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,MAAI,UAAU,EAAG,QAAO;AACxB,QAAM,OAAO,WAAW,KAAK,KAAK,KAAK;AAEvC,MAAI,QAAQ,EAAG,QAAO;AACtB,MAAI,QAAQ,GAAI,QAAO;AACvB,MAAI,QAAQ,GAAI,QAAO;AACvB,SAAO;AACT;AAGA,SAAS,mBAAmB,KAAmB;AAG7C,MAAI,IAAI,SAAS,MAAM,IAAI,SAAS,KAAK;AACvC,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AAEA,MAAI,CAAC,WAAW,KAAK,GAAG,GAAG;AACzB,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AACF;AAQA,SAAS,WAAW,KAA6B;AAC/C,QAAM,QAAQ,IAAI,YAAY;AAC9B,SAAO,MAAM,WAAW,SAAS,KAAK,MAAM,WAAW,SAAS,IAAI,SAAS;AAC/E;AAEA,eAAsB,SAAS,KAAmC;AAChE,qBAAmB,GAAG;AACtB,iBAAe;AAEf,MAAI,UAAU;AACd,MAAI;AACF,UAAM,MAAM,MAAM,gBAAY,GAAG;AAEjC,QAAI,CAAC,IAAI,WAAW;AAClB,YAAM,IAAI,MAAM,IAAI,SAAS,mBAAmB;AAAA,IAClD;AAEA,UAAM,UAAuB;AAAA,MAC3B;AAAA,MACA,YAAY,IAAI,SAAS;AAAA,MACzB,QAAQ;AAAA,MACR,eAAe,IAAI,KAAK;AAAA,MACxB,cAAc,IAAI,KAAK;AAAA,MACvB,MAAM,WAAW,GAAG;AAAA,MACpB,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,WAAW,IAAI,YAAY;AAAA,MAC3B,kBAAiB,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC1C;AAEA,UAAM,YAAY,OAAO;AACzB,cAAU;AACV,WAAO;AAAA,EACT,UAAE;AACA,kBAAc,OAAO;AAAA,EACvB;AACF;AASA,SAAS,eAAe,KAAuB;AAC7C,QAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,SAAO,uEAAuE,KAAK,GAAG;AACxF;AAEA,eAAsB,WAAW,SAAmD;AAClF,MAAI;AACF,UAAM,MAAM,MAAM,gBAAY,QAAQ,KAAK,QAAQ,UAAU;AAE7D,QAAI,IAAI,OAAO;AACb,YAAM,UAAuB;AAAA,QAC3B,GAAG;AAAA,QACH,kBAAiB,oBAAI,KAAK,GAAE,YAAY;AAAA,QACxC,QAAQ;AAAA,QACR,WAAW,IAAI,YAAY;AAAA,MAC7B;AACA,YAAM,YAAY,OAAO;AACzB,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,EAAE,GAAG,SAAS,QAAQ,UAAU,CAAC;AACnD,WAAO;AAAA,EACT,SAAS,KAAK;AAEZ,QAAI,eAAe,GAAG,GAAG;AACvB,aAAO,oBAAoB,OAAO,IAAI,UAAU;AAAA,IAClD;AAEA,UAAM,YAAY,EAAE,GAAG,SAAS,QAAQ,UAAU,CAAC;AACnD,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,WAAW,SAA2D;AAC1F,MAAI,gBAAgB;AACpB,WAAS,UAAU,GAAG,UAAU,GAAG,WAAW;AAC5C,QAAI;AACF,YAAM,kBAAc,QAAQ,KAAK,QAAQ,UAAU;AACnD,sBAAgB;AAChB;AAAA,IACF,QAAQ;AACN,UAAI,UAAU,EAAG,OAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,GAAI,CAAC;AAAA,IAC7D;AAAA,EACF;AACA,QAAM,aAAa;AACnB,SAAO,EAAE,cAAc;AACzB;;;AH/WA,IAAM,mBAAmBC,MAAK,UAAU,kBAAkB;AAI1D,eAAsB,iBAA6C;AACjE,MAAI;AACF,UAAM,MAAM,MAAMC,UAAS,kBAAkB,OAAO;AACpD,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,eAAe,QAAmC;AACtE,QAAM,UAAU,mBAAmB;AACnC,QAAMC,WAAU,SAAS,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG;AAAA,IACxD,UAAU;AAAA,IACV,MAAM;AAAA,EACR,CAAC;AACD,QAAMC,QAAO,SAAS,gBAAgB;AACxC;AAWA,SAAS,gBACP,eACA,eACA,gBACgB;AAChB,QAAM,YAA4B,CAAC;AAEnC,QAAM,kBAAkB,IAAI,IAAI,cAAc,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AACtF,QAAM,eAAe,IAAI,IAAI,cAAc,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhF,aAAW,WAAW,eAAe;AACnC,QAAI,QAAQ,cAAc,eAAgB;AAG1C,eAAW,iBAAiB,QAAQ,SAAS,UAAU;AACrD,YAAM,eAAe,gBAAgB,IAAI,cAAc,IAAI;AAC3D,UAAI,iBAAiB,UAAa,iBAAiB,cAAc,SAAS;AACxE,kBAAU,KAAK;AAAA,UACb,aAAa,cAAc;AAAA,UAC3B,aAAa;AAAA,UACb;AAAA,UACA,eAAe,QAAQ;AAAA,UACvB,eAAe,cAAc;AAAA,QAC/B,CAAC;AAAA,MACH;AAAA,IACF;AAGA,eAAW,cAAc,QAAQ,SAAS,OAAO;AAC/C,YAAM,eAAe,aAAa,IAAI,WAAW,IAAI;AACrD,UAAI,iBAAiB,UAAa,iBAAiB,WAAW,SAAS;AACrE,kBAAU,KAAK;AAAA,UACb,aAAa,WAAW;AAAA,UACxB,aAAa;AAAA,UACb;AAAA,UACA,eAAe,QAAQ;AAAA,UACvB,eAAe,WAAW;AAAA,QAC5B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAIA,eAAe,cAAc,SAAsB,YAAqC;AACtF,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,QAAM,EAAE,WAAW,IAAI,IAAI,IAAI,eAAe,SAAS,UAAU;AACjE,QAAM,WAAyB;AAAA,IAC7B,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb;AACA,QAAM,kBAAkB,QAAQ;AAChC,SAAO;AACT;AAEA,eAAe,wBAAyC;AAGtD,QAAM,UAAU,MAAM,YAAY;AAClC,MAAI,CAAC,WAAW,CAAC,QAAQ,KAAK;AAC5B,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AACA,SAAO,QAAQ;AACjB;AAEA,SAAS,aAAa,UAAuB,YAAuC;AAClF,SAAO;AAAA,IACL,UAAU;AAAA,MACR,GAAG,SAAS;AAAA,MACZ,CAAC,WAAW,SAAS,GAAG;AAAA,IAC1B;AAAA,EACF;AACF;AAIA,eAAsB,KACpB,OACA,iBACqB;AACrB,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AAEA,QAAM,YAAY,MAAM,kBAAkB;AAC1C,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,WAAW,CAAC;AAAA,MACZ,eAAe;AAAA,MACf,OAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,sBAAsB;AAE/C,MAAI,kBAAsC;AAE1C,MAAI;AACF,UAAM,WAAW,MAAM,iBAAiB;AACxC,QAAI,UAAU;AACZ,wBAAkB,eAAe,SAAS,WAAW,SAAS,IAAI,SAAS,KAAK,UAAU;AAAA,IAC5F;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,KAAK,4DAA4D,EAAE,OAAO,OAAO,GAAG,EAAE,CAAC;AAC9F,sBAAkB;AAAA,EACpB;AAGA,QAAM,WAAW,MAAM,gBAAgB;AACvC,QAAM,YAAY,MAAM,aAAa;AACrC,QAAM,cAAc,SAAS;AAE7B,QAAM,aAA2B;AAAA,IAC/B;AAAA,IACA;AAAA,IACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC;AAAA,IACA,GAAI,kBAAkB,EAAE,UAAU,gBAAgB,IAAI,CAAC;AAAA,EACzD;AAGA,QAAM,gBAAgB,kBAClB,OAAO,OAAO,gBAAgB,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,cAAc,SAAS,IAC/E,CAAC;AAEL,QAAM,YAAY,gBAAgB,UAAU,eAAe,SAAS;AAMpE,QAAM,cAA2B,mBAAmB,EAAE,UAAU,CAAC,EAAE;AACnE,QAAM,gBAAgB,aAAa,aAAa,UAAU;AAE1D,MAAI,UAAU,SAAS,GAAG;AAExB,UAAM,cAAc,eAAe,UAAU;AAC7C,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA,eAAe;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,MAAM,MAAM,cAAc,eAAe,UAAU;AAGzD,QAAM,iBAAiB,MAAM,eAAe;AAC5C,QAAM,eAAe;AAAA,IACnB,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA,GAAI,kBAAkB,CAAC;AAAA,IACvB,UAAU;AAAA,EACZ,CAAC;AAED,SAAO,KAAK,gCAAgC,EAAE,WAAW,UAAU,OAAO,KAAK,cAAc,QAAQ,EAAE,OAAO,CAAC;AAE/G,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW,CAAC;AAAA,IACZ,eAAe;AAAA,EACjB;AACF;AAIA,eAAsB,yBACpB,SACA,aACA,gBACe;AAEf,QAAM,iBAA8B;AAAA,IAClC,UAAU,EAAE,GAAG,QAAQ,SAAS;AAAA,EAClC;AAEA,aAAW,EAAE,UAAU,WAAW,KAAK,aAAa;AAClD,QAAI,eAAe,aAAc;AAGjC,UAAM,eAAe,eAAe,SAAS,cAAc;AAC3D,QAAI,CAAC,cAAc;AACjB,aAAO,KAAK,mEAAmE,EAAE,eAAe,CAAC;AACjG;AAAA,IACF;AACA,QAAI,SAAS,gBAAgB,WAAW;AACtC,qBAAe,SAAS,cAAc,IAAI;AAAA,QACxC,GAAG;AAAA,QACH,UAAU;AAAA,UACR,GAAG,aAAa;AAAA,UAChB,UAAU,aAAa,SAAS,SAAS;AAAA,YAAI,CAAC,MAC5C,EAAE,SAAS,SAAS,cAChB,EAAE,GAAG,GAAG,SAAS,SAAS,cAAc,IACxC;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,qBAAe,SAAS,cAAc,IAAI;AAAA,QACxC,GAAG;AAAA,QACH,UAAU;AAAA,UACR,GAAG,aAAa;AAAA,UAChB,OAAO,aAAa,SAAS,MAAM;AAAA,YAAI,CAAC,MACtC,EAAE,SAAS,SAAS,cAChB,EAAE,GAAG,GAAG,SAAS,SAAS,cAAc,IACxC;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,sBAAsB;AAC/C,QAAM,cAAc,gBAAgB,UAAU;AAC9C,SAAO,KAAK,sCAAsC,EAAE,OAAO,YAAY,OAAO,CAAC;AACjF;","names":["readFile","writeFile","rename","join","readFile","writeFile","rename","createCipheriv","createDecipheriv","randomBytes","scryptSync","hkdfSync","ENCRYPTION_SECRET","HKDF_SALT","_legacyKey","deriveEncryptionKey","hkdfSync","deriveLegacyKey","scryptSync","randomBytes","createCipheriv","createDecipheriv","readFile","writeFile","rename","join","readFile","writeFile","rename"]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  HISTORY_PATH,
3
3
  ensureDataDirs
4
- } from "./chunk-UWS4A4F5.js";
4
+ } from "./chunk-EHIBIFCB.js";
5
5
 
6
6
  // src/lib/history/history-logger.ts
7
7
  import { readFile, writeFile, rename, open, unlink } from "fs/promises";
@@ -86,4 +86,4 @@ export {
86
86
  appendEntry,
87
87
  clearHistory
88
88
  };
89
- //# sourceMappingURL=chunk-KVCVIRWI.js.map
89
+ //# sourceMappingURL=chunk-Z2VN4VYQ.js.map
@@ -0,0 +1,12 @@
1
+ import {
2
+ checkCompliance,
3
+ versionAtLeast
4
+ } from "./chunk-5MYWF5D7.js";
5
+ import "./chunk-PVSE6XO7.js";
6
+ import "./chunk-EHIBIFCB.js";
7
+ import "./chunk-KDHEUNRI.js";
8
+ export {
9
+ checkCompliance,
10
+ versionAtLeast
11
+ };
12
+ //# sourceMappingURL=compliance-checker-7NMFKWTI.js.map
@@ -3,12 +3,12 @@ import {
3
3
  clearHistory,
4
4
  detectAction,
5
5
  loadHistory
6
- } from "./chunk-KVCVIRWI.js";
7
- import "./chunk-UWS4A4F5.js";
6
+ } from "./chunk-Z2VN4VYQ.js";
7
+ import "./chunk-EHIBIFCB.js";
8
8
  export {
9
9
  appendEntry,
10
10
  clearHistory,
11
11
  detectAction,
12
12
  loadHistory
13
13
  };
14
- //# sourceMappingURL=history-logger-PBDOLKNJ.js.map
14
+ //# sourceMappingURL=history-logger-ZGYRAFON.js.map