Files
AeroFetch/src/main/templates.ts
T
debont80 1376c2dee8 Harden audit findings: correctness, type-safety, Windows conventions & polish
Audit-pass over CODE-AUDIT.md (~48 items closed this pass; all verified —
typecheck + 234 tests + eslint + prettier green).

Correctness / bugs:
- B3: match the release checksum to the asset's filename line (no wrong-hash verify)
- B4: newline-safe metadata probe (one --print with a unit-separator delimiter)
- B5 / L88: guard the meta event against canceled items; progress no longer promotes
  a queued item outside pump()
- B7: cookie-login promise always resolves (handles destroy-without-close)
- L146: trim parser rejects >2 colon-group times; M36: Library selection counts only
  actionable rows
- L11 / L50 / L156 / L57 / L159 / L15 / L3: live queue count, empty-cookie message,
  schedule picker min, dead-code/comment cleanup

Type safety:
- Enable noUncheckedIndexedAccess + noFallthroughCasesInSwitch (15 real edge cases fixed)

Resilience / Windows / metadata:
- R5: settings write failure handled (no unhandled IPC rejection; reconciles to truth)
- W1 / W5 / W6: min window size, seeded folder picker, parented sign-in window;
  L147 dead macOS branches removed
- CL1: shared stdout markers; package/builder metadata (license, homepage, repository,
  copyright, tsbuildinfo glob)

Copy / docs / tests:
- M37 / SR9 dev-jargon cleanup in hints; M8 / M25 / M26 / L66 / L80 / L81 reconciled
- New unit tests for L35 (isValidMediaItem) and L36 (compareVersions)

This commit also checkpoints the previously-uncommitted feat/tray-background-clipboard
work it builds on: background running + auto-download, library clipboard detection,
tray, binary management & library scale, credential encryption at rest, the shared
jsonStore and ui/ primitives, and the eslint/prettier tooling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 13:02:54 -04:00

46 lines
1.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { CommandTemplate } from '@shared/ipc'
import { isTemplateLike } from './validation'
import { createJsonStore } from './jsonStore'
// Plain JSON in userData, same shape as history.ts. Atomic writes / corruption
// backup / caching come from the shared jsonStore (R1R3).
const MAX_TEMPLATES = 100
// A persisted template entry must at least be an object carrying an id (see
// isTemplateLike in validation.ts); everything else is coerced by sanitize().
// Drop anything that isn't, so a hand-edited templates.json can't inject
// malformed entries. (audit S5)
const store = createJsonStore('templates.json', isTemplateLike, MAX_TEMPLATES)
export function listTemplates(): CommandTemplate[] {
// Normalise each surviving entry through sanitize() so name/args are always
// well-formed strings regardless of what was on disk.
return store.read().map(sanitize)
}
function sanitize(t: CommandTemplate): CommandTemplate {
const urlPattern = typeof t.urlPattern === 'string' ? t.urlPattern.trim() : ''
return {
id: String(t.id),
name: (t.name ?? '').trim() || 'Untitled command',
args: (t.args ?? '').trim(),
// Only persist a urlPattern when one was provided, keeping older files clean.
...(urlPattern ? { urlPattern } : {})
}
}
/** Add a new template, or update an existing one (matched by id). */
export function saveTemplate(template: CommandTemplate): CommandTemplate[] {
const clean = sanitize(template)
return store.write([clean, ...listTemplates().filter((t) => t.id !== clean.id)])
}
export function removeTemplate(id: string): CommandTemplate[] {
return store.write(listTemplates().filter((t) => t.id !== id))
}
/** Replace the entire template list (backup restore) rather than merge-by-id. */
export function replaceTemplates(templates: CommandTemplate[]): CommandTemplate[] {
return store.write(templates.map(sanitize))
}