saravanakumardb1
29605da16d
fix(admin-web): implement debug-session JSON download, remove console.log
2026-03-21 23:13:58 -07:00
saravanakumardb1
ead9457345
feat(platform+admin-web): implement 4 missing backend endpoints + re-enable frontend
...
Backend endpoints added:
- POST /delivery/logs/:id/retry — re-dispatches failed email deliveries (Q1)
- POST /reviews/:id/flag — flags review item with reason + admin metadata (Q2)
- DELETE /agent-evals/suites/:id — deletes evaluation suite with 204 response (Q3)
Frontend re-enabled:
- delivery: retry button for failed entries
- reviews: flag dropdown menu item
- agent-evals: delete dropdown menu item + Trash2 icon
Frontend fixed:
- webhooks: per-subscription delivery loading via GET /subscriptions/:id/deliveries (Q4)
2026-03-21 23:11:38 -07:00
saravanakumardb1
1935b39525
docs(admin-web): update gap analysis — all page proxy routes verified complete
...
- Add batch 4 fixes: experiments/ab-testing proxy routes, webhooks B20 fix
- Add verification section: all 30 API call paths have matching proxy routes
- Update statistics: 46 proxy route dirs, 20 broken calls fixed, 0 missing for pages
- Add TODO Q4: webhooks per-subscription delivery loading
- Update 'Still Missing' table with better notes (none are blocking)
2026-03-21 23:00:35 -07:00
saravanakumardb1
8c45e440df
feat(admin-web): add experiments + ab-testing proxy routes, fix webhooks deliveries
...
New proxy routes:
- /api/experiments → rewrites to /api/ab-testing/experiments (base + catch-all)
- /api/ab-testing/[...path] → /api/ab-testing/* (for suggestions, hypotheses)
Bug fix:
- B20: webhooks page called GET /webhooks/deliveries (404) — removed broken call,
backend only has GET /webhooks/subscriptions/:id/deliveries (TODO Q4)
2026-03-21 22:56:22 -07:00
saravanakumardb1
6d9b687b49
docs(admin-web): update gap analysis with batch 2+3 fixes + new proxy routes
...
- Add batch 2 bug fixes table (587d22e ): orgs members→memberships, marketplace admin paths
- Add batch 3 bug fixes table (c54a3fe ): agent-evals run plural, delete disabled
- Add missing proxy routes section (880338b ): ai-diagnostics, feedback
- Update statistics: 43 proxy route dirs, 19 total API call fixes, ~10 remaining
- Add TODO Q3: agent-evals suite delete endpoint needed
2026-03-21 21:19:27 -07:00
saravanakumardb1
880338b79c
feat(admin-web): add missing proxy routes for ai-diagnostics + feedback pages
...
- ai-diagnostics: GET/POST /api/ai-diagnostics/* → platform-service /api/ai-diagnostics/*
- feedback: GET/POST/DELETE /api/feedback/* → platform-service /api/feedback/*
- feedback base: GET/POST /api/feedback → platform-service /api/feedback
These pages existed with sidebar items but had no proxy routes, causing 404s.
2026-03-21 21:17:04 -07:00
saravanakumardb1
c54a3fe277
fix(admin-web): fix agent-evals run endpoint + disable delete (no backend)
...
- B18: POST /agent-evals/suites/:id/run → /suites/:id/runs (plural)
- B19: DELETE /agent-evals/suites/:id has no backend endpoint — disabled with TODO Q3
2026-03-21 21:14:52 -07:00
saravanakumardb1
587d22e107
fix(admin-web): correct 4 more broken API calls in organizations + marketplace
...
Organizations fixes:
- B13: GET /orgs/:id/members → GET /orgs/:id/memberships (match backend)
- B14: DELETE /orgs/:id/delete → DELETE /orgs/:id (no suffix needed)
Marketplace fixes:
- B16: GET /marketplace/listings → GET /marketplace/admin/pending (admin view)
- B17: POST /marketplace/listings/:id/approve → POST /marketplace/admin/:id/approve
- B17: POST /marketplace/listings/:id/reject → POST /marketplace/admin/:id/reject
2026-03-21 21:12:32 -07:00
saravanakumardb1
a1fd1d2e37
docs(admin-web): update gap analysis with implementation status + bug fix log
...
- Add Implementation Status section with checkboxes for all completed work
- Sprint 0-4 items all checked off (sidebar, pages, proxy routes)
- Document 12 API call bugs found and fixed in a3e94f3
- Track 11 remaining missing proxy routes
- Track 2 open TODOs (Q1: delivery retry, Q2: reviews flag)
- Update Part 6 statistics with before/after columns
- Admin gap reduced from 28 missing to ~11
2026-03-21 21:08:47 -07:00
saravanakumardb1
a3e94f3f3d
fix(admin-web): correct 12 broken API calls across 5 pages
...
Pages fixed:
- waitlist: GET /waitlist/list → GET /waitlist (root)
- delivery: GET /delivery/log → GET /delivery/logs; disable retry button (no backend endpoint)
- reviews: GET /reviews/list → GET /reviews; approve/reject → POST /:id/decision with body; disable flag (no endpoint)
- jobs: GET /jobs/list → GET /jobs; GET /runs/list → GET /runs; trigger → POST /jobs/trigger with {jobId}
- gdpr-export: GET /exports/list → GET /exports; POST /exports/create → POST /exports
TODO Q1: delivery retry endpoint not implemented in backend
TODO Q2: reviews flag endpoint not implemented in backend
2026-03-21 21:06:49 -07:00
saravanakumardb1
edf8926d6d
fix(docs): self-audit Portal PRD + roadmap — 15 findings corrected
...
Review Errata (15 findings):
- F1-F2: Product count 11→10 (ByteLyst Auth has no backend)
- F3: product.json count 4→3 missing (FlowMonk, ActionTrail, LocalMemGPT)
- F4: Architecture diagram spacing fixes
- F5: Remove portalLayout from GlobalPreferences (contradicted separate Cosmos container)
- F6-F7: Widget endpoint unified to /widgets/:widgetId/data + added layout CRUD endpoints
- F8: Verified all 10 feed source endpoints against actual backend route files
- F9: Added @bytelyst/datastore to BFF tech stack
- F10: Added Cosmos containers section (portal_widget_layouts)
- F11: Global prefs dependency Phase 2→Phase 5 blocker
- F12: Removed emojis from search example
- F13: Added quick-actions task to roadmap Phase 1
- F14: Added 4 missing scaffold tasks (errors, datastore, cosmos-init, vitest)
- F15: Corrected run-local-all-services.sh location
- Updated task totals: 124→129
2026-03-21 20:57:28 -07:00
saravanakumardb1
7a4cca034c
docs: add Unified ByteLyst Portal PRD + phased roadmap with 124 tasks
...
- PRD: product identity, architecture (BFF + web), data model, 10 pages,
21 widgets, cross-product feed/search, security, resilience, telemetry
- Roadmap: 8 phases (scaffold, auth, feed, widgets, search, billing,
security, polish), dependency graph, ~21 days estimated
- Builds on CROSS_PRODUCT_USER_DASHBOARD.md design + DASHBOARD_UI_GAP_ANALYSIS.md findings
2026-03-21 20:49:55 -07:00
saravanakumardb1
0b8e45a9b0
fix(admin-web): jobs proxy route missing PATCH+DELETE exports — page uses PATCH in handleToggle
2026-03-21 20:46:53 -07:00
saravanakumardb1
e5ffdad8e8
fix(admin-web): jobs page uses PUT instead of PATCH — matches backend API
2026-03-21 20:44:00 -07:00
saravanakumardb1
daf1f90706
fix(admin-web): maintenance page API path mismatches + base proxy route
...
- maintenance page: 'status' → 'full' (GET /settings/maintenance/full)
- maintenance page: 'mode' POST → '' PUT (PUT /settings/maintenance)
- Add maintenance base route.ts for root-level GET/PUT proxy
2026-03-21 20:37:32 -07:00
saravanakumardb1
ce0074d6ee
fix(admin-web): proxy routes + pages use cookie-based auth
...
- Add getCurrentUserFromRequest() to auth-server.ts (checks cookies first, then Authorization header)
- Update all 34 proxy routes: getCurrentUser(req.headers.get('authorization')) → getCurrentUserFromRequest(req)
- Add createProxyFetch() shared helper in lib/proxy-fetch.ts (injects auth + product-id headers)
- Update 15 admin pages: replace inline fetch helpers with createProxyFetch
- Root cause: newer pages used bare fetch() without Authorization headers, causing 401s on all proxy routes
2026-03-21 20:31:30 -07:00
saravanakumardb1
f9fa583cae
docs: add ecosystem consistency audit — 20 findings across 13 repos
2026-03-21 20:21:06 -07:00
saravanakumardb1
dba594d4eb
fix(admin-web): GDPR export routes — create exports proxy + fix page paths
...
- Create /api/exports/[...path] proxy route for platform-service exports module
- Fix gdpr-export page: /api/maintenance/gdpr-exports → /api/exports/list|create
- Old path routed to settings/maintenance which has no export endpoints
2026-03-21 20:18:37 -07:00
saravanakumardb1
7b6aa53d68
fix(admin-web): proxy route path mismatches + missing HTTP methods
...
- maintenance: fix path /api/maintenance → /api/settings/maintenance
- maintenance: replace PATCH with PUT + add DELETE (matches backend API)
- ip-rules: fix path /api/ip-rules → /api/ratelimit/ip-rules
- jobs: add missing PUT handler for job updates
2026-03-21 20:12:24 -07:00
saravanakumardb1
633fe855bf
fix(admin-web): runs proxy route — same DELETE body-forwarding fix
2026-03-21 18:19:28 -07:00
saravanakumardb1
b6f9636171
fix(admin-web): proxy routes forward body on DELETE — use method !== GET/HEAD guard
2026-03-21 18:18:26 -07:00
saravanakumardb1
e712113c30
fix(admin-web): remove 38 unused imports across 13 dashboard pages
2026-03-21 18:13:29 -07:00
saravanakumardb1
e0bc38c365
feat(admin-web): Phase 4 — event-subscriptions, ip-rules, maintenance, sessions, status, gdpr-export pages
2026-03-21 18:05:14 -07:00
saravanakumardb1
aaceba2ee5
feat(admin-web): Phase 2 — webhooks, knowledge, agent-evals, reviews, marketplace, delivery, jobs pages
2026-03-21 17:53:44 -07:00
saravanakumardb1
aa33b12f8c
feat(admin-web): Phase 1 — organizations, support, AI budgets, waitlist pages
2026-03-21 17:47:41 -07:00
saravanakumardb1
d1d01727e4
fix(platform): register ai-diagnostics routes + wire 6 hidden sidebar pages
...
Phase 0 from DASHBOARD_UI_COVERAGE_ROADMAP:
- Register ai-diagnostics routes in server.ts (671-line module was never mounted)
- Add 6 hidden pages to admin sidebar-nav.tsx:
Debug Sessions, Health Dashboard, Extraction, Experiments,
Predictive, AI Diagnostics
- /users was already in sidebar (no change needed)
- Kill switch verified: already per-product via productId query param
- Admin sidebar now has 33 items (was 27)
2026-03-21 17:40:35 -07:00
saravanakumardb1
6f9ff2a5a4
docs: fix 10 bugs in dashboard UI coverage roadmap — self-audit corrections
...
Systematic review found and corrected:
- R1: Gap 1.2.3 (predictive campaigns) missing — added as Phase 4.12
- R2: Gap 1.2.4 (kill switch for all products) missing — added as Phase 0.3
- R3: Phase 1 labeled '1 week' but effort is 10 days — fixed to '2 weeks'
- R4: Admin sidebar target 59 wrong — corrected to 52
- R5: Phase 4 sidebar count 9 wrong — fixed to 7 new + 5 expanded
- R6: Dependency graph incorrect — Phase 4 can start after Phase 1
- R7: Success metrics denominator misleading — clarified
- R8: No grand total effort — added ~60 dev-days
- R9: No completion tracking — noted
- R10: Phase 2 API route count unexplained — added note
All 55 gap analysis items now verified covered across phases 0-6.
2026-03-21 17:35:30 -07:00
saravanakumardb1
d1a4db29a4
docs: add dashboard UI coverage roadmap — 6-phase execution plan to close 55 gaps
...
Converts gap analysis findings into concrete phased roadmap:
- Phase 0: Fix ai-diagnostics backend bug + wire 7 hidden sidebar items (1 day)
- Phase 1: 4 critical admin pages — orgs, support, AI budgets, waitlist (1 week)
- Phase 2: 7 high-value admin pages — webhooks, knowledge, evals, reviews, marketplace, delivery, jobs (2 weeks)
- Phase 3: User dashboard security hub + 5 missing pages (1.5 weeks)
- Phase 4: 11 operational admin features — event bus, SCIM, IP rules, backups, etc. (2 weeks)
- Phase 5: User polish — feedback, org membership, marketplace, GDPR export (1 week)
- Phase 6: 14 backlog items triggered by product needs
Includes dependency graph, per-page template, effort estimates,
acceptance criteria, success metrics, and risk register.
2026-03-21 17:31:19 -07:00
saravanakumardb1
827934124d
docs: add comprehensive dashboard UI gap analysis — 55 hidden/underexposed features identified
...
Systematic scan of platform-service (43+ modules, 511+ endpoints) vs admin-web
(27 sidebar items, 38 pages) and user-dashboard-web (11 pages, 39 API routes).
Key findings:
- 28 backend modules completely missing from admin UI
- 7 admin pages built but missing from sidebar (undiscoverable)
- 12 user-dashboard features completely missing
- 1 critical backend bug: ai-diagnostics routes.ts not registered in server.ts
- 26 missing admin API proxy routes
- 10 errata items self-audited and corrected in-place
Includes 79-row module-to-UI matrix, auth sub-module gap detail,
prioritized 6-sprint action plan, and cross-cutting gap tables.
2026-03-21 17:18:06 -07:00
saravanakumardb1
267f8af3a4
test(ai-diagnostics): add 94 tests for error-normalization, clustering, query-parser
2026-03-21 17:06:24 -07:00
saravanakumardb1
9471d4c56f
fix(test): add @vitest-environment happy-dom to React UI test files
...
6 test files across 4 packages (auth-ui, dashboard-components,
dashboard-shell, react-auth) failed with 'document is not defined'
when run from the monorepo root because the root vitest config uses
environment: 'node'. The package-local configs set happy-dom but are
ignored when vitest is invoked from root.
Fix: Add per-file '// @vitest-environment happy-dom' annotations,
which is the recommended vitest pattern for mixed-environment monorepos.
This ensures tests work regardless of which config is loaded.
Recovers 148 tests across 6 files.
2026-03-21 16:21:42 -07:00
saravanakumardb1
22780b0e7e
fix(scripts): add tsconfig.json — fixes pnpm typecheck failure
...
The scripts/ workspace member had no tsconfig.json, so 'tsc --noEmit'
printed help text and exited 1, breaking 'pnpm typecheck' across the
entire monorepo.
2026-03-21 15:55:27 -07:00
saravanakumardb1
2c6397272f
fix(test): add env defaults to platform-service vitest config
...
Aligns service-local vitest.config.ts with root config so tests pass
both via 'pnpm test' (uses service config) and 'npx vitest run' (uses root).
Fixes telemetry.test.ts which fails because its import chain eagerly
loads config.ts → envSchema.parse() requiring COSMOS_ENDPOINT/KEY/JWT_SECRET.
Added: RATE_LIMIT_STORE_MODE=memory, COSMOS_ENDPOINT, COSMOS_KEY, JWT_SECRET
(all test-safe placeholders, never used at runtime with DB_PROVIDER=memory)
2026-03-21 15:32:14 -07:00
saravanakumardb1
7613d6890f
feat(field-encrypt): admin-panel encryption toggle via feature flags
...
- FieldEncryptorConfig.enabled: false returns NullFieldEncryptor (no-op)
- NullFieldEncryptor stores plaintext as-is, decrypt returns ct directly
- 7 new tests for toggle behavior (50/50 total)
- encryption_enabled added to COMMON_FLAGS (seeded for all 10 products)
2026-03-21 15:24:19 -07:00
saravanakumardb1
4de3974a26
docs(agents): add scripts/ workspace member + encryption migration CLI to AGENTS.md
...
- scripts/ directory in repo layout with encrypt-migrate.ts + package.json
- pnpm-workspace.yaml now includes scripts
- Encryption migration CLI commands in build/test section
2026-03-21 13:46:08 -07:00
saravanakumardb1
b1af8e550a
docs(e2ee): detailed SQLCipher + AKV implementation plan for LocalMemGPT Sprint 5.4
...
- Decision: SQLCipher full-DB encryption (preserves FTS5 search)
- Key hierarchy: AKV secret > env var > auto-generated file > unencrypted dev
- Existing DB migration via sqlcipher_export
- 6 implementation steps documented
2026-03-21 13:39:01 -07:00
saravanakumardb1
10b48a3800
feat(admin-web): add ActionTrail integration page
...
- New /actiontrail page with 4 tabs: Timeline, Agents, Alerts, Approvals
- Summary cards: total actions, critical/high count, pending approvals, active alerts
- Risk-level filtering on timeline, color-coded risk badges
- Server-side API proxy route (/api/actiontrail) to ActionTrail backend (port 4018)
- actiontrail-client.ts: typed API client using @bytelyst/api-client
- Sidebar nav item with Crosshair icon
- ACTIONTRAIL_SERVICE_URL added to .env.example
- Graceful fallback when ActionTrail service is unavailable
2026-03-21 13:20:15 -07:00
saravanakumardb1
c252cfd198
feat(devops): encryption migration CLI with embedded product configs
...
- scripts/encrypt-migrate.ts — batch-encrypt existing plaintext Cosmos docs
- scripts/ added as pnpm workspace member for clean @bytelyst/* imports
- 10 product configs, 20 containers, 40+ fields
- --dry-run, --product, --container, --batch-size, --verbose flags
- Idempotent via __encrypted sentinel (migrateDocuments helper)
- Updated E2EE roadmap Sprint 6.2 as complete
2026-03-21 13:19:55 -07:00
saravanakumardb1
cf9617cda5
docs(workspace): add health dashboard prompt
2026-03-21 12:40:51 -07:00
saravanakumardb1
bb1069930b
docs(workspace): add coverage remediation prompt
2026-03-21 12:40:38 -07:00
saravanakumardb1
89b38cadfa
docs(workspace): add coverage audit prompt
2026-03-21 12:40:12 -07:00
saravanakumardb1
4a47db72ae
fix(flags): SSE stream endpoint + client — pass productId via query string
...
EventSource API cannot set custom headers, so the SSE /flags/stream
endpoint and feature-flag-client were broken for streaming mode:
- Server: accept productId and token from query string as fallback
when x-product-id / authorization headers are absent
- Client: pass productId (and optional auth token) as query params
when constructing the EventSource URL
2026-03-21 12:12:14 -07:00
saravanakumardb1
0b16cb4d63
fix(test): add test env defaults to root vitest config — fixes 35 pre-existing failures
...
Root vitest.config.ts now sets:
- DB_PROVIDER=memory — datastore uses MemoryDatastoreProvider (no Cosmos needed)
- RATE_LIMIT_STORE_MODE=memory — ratelimit store uses in-memory sliding window
- COSMOS_ENDPOINT, COSMOS_KEY, JWT_SECRET — test-safe placeholders so config.ts
Zod parse succeeds (never used at runtime with DB_PROVIDER=memory)
This fixes 35 pre-existing test failures across 6 files when running from root:
- ratelimit.test.ts (15 tests) — was hitting Cosmos path
- diagnostics.test.ts (4 tests) — was hitting Cosmos path
- auto-register.test.ts (8 tests) — config parse failed
- onboarding.test.ts (1 test) — config parse failed
- telemetry.test.ts (suite) — config parse failed via event-bus import chain
- cross-product.test.ts (6 tests) — config parse failed
Platform-service: 117/117 files, 1389/1389 tests (was 1251 passing)
2026-03-21 12:06:34 -07:00
saravanakumardb1
32afe8dde7
docs(e2ee): update roadmap — ChronoMind + PeakPulse backends encrypted (9 total)
...
- ChronoMind: timers.description, routines.description, routines.steps[].notes (182 tests)
- PeakPulse: peak-sessions.notes (65 tests)
- Only MindLyst (KMP) and LocalMemGPT (SQLite) deferred
2026-03-21 12:04:10 -07:00
saravanakumardb1
1e1ee969dc
feat(flags): add seed flags for 6 missing products + 6 new evaluator edge-case tests
...
- seed.ts: add default flags for jarvisjr (3), peakpulse (3), flowmonk (2), notelett (2), actiontrail (2), localmemgpt (2)
Previously only chronomind, nomgap, mindlyst, smartauth, lysnrai had seed flags — common flags (maintenance_mode, telemetry_enabled) were not seeded for newer products
- flags.test.ts: 63 → 69 tests (+6):
- anonymous user with partial percentage returns off
- partial rule rollout (0%) skips even matching users
- neq operator (not equal)
- contains operator
- gte + lt numeric range on custom attributes
- missing context attribute returns off
2026-03-21 11:52:08 -07:00
saravanakumardb1
dd113b96c9
fix(flags): critical partition key bug + audit snapshot integrity + anonymous rollout
...
- repository.ts: update() and remove() now require productId as partition key
(was passing 'id' as both params — works with memory provider but fails on Cosmos DB)
- repository.ts: updateSegment() and removeSegment() also fixed
- routes.ts: all repo.update/remove calls updated to pass productId
- routes.ts: audit 'before' snapshots now use JSON deep copy instead of shallow spread
(prevents nested object mutation from corrupting audit trail)
- routes.ts: kill switch audit now uses repo.update() return value for 'after' snapshot
- evaluator.ts: anonymous users (no userId) with partial percentage (0 < pct < 100)
now correctly return 'off' instead of falling through to default variation
(can't deterministically hash without a userId)
2026-03-21 11:50:08 -07:00
saravanakumardb1
ca6a4d41d8
feat(flags): production-grade feature flag system — multi-variate, segments, audit, SSE, scheduling, prerequisites
...
- types.ts: multi-variate flags (boolean/string/number/JSON), targeting rules with 18 operators, scheduling (enableAt/disableAt/gradual rollout), prerequisites, segments, audit log, evaluation context
- evaluator.ts: pure evaluation engine — schedule checking, prerequisite dependencies (circular detection), individual targeting, targeting rules (AND clauses), segment matching, percentage rollout (FNV-1a), OS version/platform/region filtering
- repository.ts: 3 collections — feature_flags, flag_segments, flag_audit_log
- routes.ts: 18 endpoints — flag CRUD, toggle, archive, kill switch (with tag filter), segment CRUD, audit log, POST /flags/evaluate (multi-variate), SSE /flags/stream, legacy /flags/poll backward-compat
- seed.ts: updated to produce full FeatureFlagDoc with variations, version
- flags.test.ts: 63 tests — schema validation, evaluator engine, targeting rules, segments, prerequisites, scheduling, gradual rollouts, multi-variate, version comparison, deterministic hashing
- @bytelyst/events: added flag.created, flag.updated, flag.deleted, flag.kill_switch event types
- @bytelyst/feature-flag-client: multi-variate support (getValue, getEvaluation, getAllEvaluations), SSE streaming mode, onChange listeners, auth token injection
- event-dispatcher.ts + webhooks/types.ts: wired new flag events
2026-03-21 11:44:49 -07:00
saravanakumardb1
d11f84da5f
docs(e2ee): update roadmap — Sprint 4 complete
...
- 4.1.2: Swift Keychain key derivation ✓
- 4.2.2: Kotlin SecureStore key derivation ✓
- 4.3: @bytelyst/client-encrypt (22 tests) ✓
- 4.4.1: @bytelyst/secure-storage-web (16 tests) ✓
- 4.5: FlowMonk tasks.description encrypted (211 tests) ✓
- Only 4.4.2 (auth-client migration) deferred to Sprint 5
2026-03-21 11:23:26 -07:00
saravanakumardb1
ce08587680
feat(secure-storage-web): create @bytelyst/secure-storage-web — encrypted IndexedDB storage
...
- IndexedDB-backed key-value store with non-extractable AES-256-GCM CryptoKey
- Key material never leaves browser crypto subsystem
- API: set, get, delete, clear, has, keys — all async
- Namespace isolation for multi-app usage
- Falls back to localStorage when SubtleCrypto unavailable
- 16 Vitest tests (fake-indexeddb), all passing
- Add IndexedDB globals to root ESLint config
2026-03-21 11:19:19 -07:00
saravanakumardb1
1bce981f43
feat(client-encrypt): create @bytelyst/client-encrypt — Web Crypto API encryption
...
- AES-256-GCM via SubtleCrypto (browsers + React Native with polyfill)
- Wire-compatible EncryptedField with @bytelyst/field-encrypt (server) and
BLFieldEncrypt (Swift/Kotlin native SDKs)
- encryptField, decryptField, generateKey, keyFromHex, keyToHex
- PBKDF2 key derivation (600k iterations per OWASP 2023)
- isEncryptedField type guard, toHex/fromHex helpers
- 22 Vitest tests, all passing
- Add Web Crypto globals to root ESLint config
2026-03-21 11:15:27 -07:00