Fixes failures across the suite that fail on main independently of any branch.
Documented + skipped
- smime/smime-crypto: this suite OOMs its worker (~4 GB heap) generating and
using real 2048-bit RSA keys via pkijs/asn1js — a pre-existing memory issue,
not a logical failure. Skipped behind a single SKIP_SMIME_CRYPTO_OOM flag with
an in-file explanation and re-enable instructions, and the beforeAll bails
early so the skipped file runs in ~2s instead of crashing the worker.
Code fixes
- jmap/client: getSubmissionAccountId honoured the requested (mail) account
even when it lacks the submission capability, so EmailSubmission/set was
addressed to the wrong account when JMAP hosts submission in a separate
account. Prefer an account that actually advertises submission, falling back
to primaryAccounts['…:submission'].
- plugin-sandbox/loader: deactivateAllSandboxed used require('./registry'),
which is unresolvable under the Vite/ESM test runtime. registry only imports
types (no cycle), so use a static import; all() already returns a copy, so
iterating while deregister mutates is safe.
Test fixes (tests trailed intentional code/behaviour changes)
- vitest.setup: add a matchMedia stub (jsdom lacks it) — unblocks 8
email-list-item tests.
- calendar-utils: pin TZ=UTC for the timezone-sensitive bounds/layout assertions
(host runs at UTC+2) and update expected minutes to UTC.
- calendar-participants: buildParticipantMap keys entries by generated UUIDs
(RFC 8984), not 'organizer'/'attendee-N'. Look entries up by identity so the
test no longer depends on a generateUUID mock leaking from another file.
- email-headers: softfail now returns the semantic 'text-warning' token.
- email-list-item: unknown keyword ids intentionally render a gray fallback badge.
- plugin-loader: exposePluginExternals is now a documented no-op.
- plugin-slot: PluginSlot reads the sandbox registry and renders iframe slots;
rewrite the tests against that architecture with a referentially stable snapshot.
- plugin-types: MAX_THEME_SIZE was raised to 2 MB.
Cleans up the lint warnings the pre-commit hook surfaces, without any
behavioral change:
- Remove unused imports/vars/destructured props (parseISO, useEffect,
format, durMin, roles, daysInYear, ALLOWED_PLUGIN_FILES, continuesBefore,
isPushConnected, isSelected) and the now-unused parseDuration import.
- Drop three stale `// eslint-disable-next-line no-undef` directives that
no longer suppress anything (browser-navigation, smime/crypto-engine).
- recurrence-expansion.test.ts: replace 39 `as any` casts with a cast-only
`rule()` helper for partial recurrence-rule fixtures, typed access to
utcStart/utcEnd (now on CalendarEvent), and the source's
`Partial<CalendarEvent> & { excluded?: boolean }` for the excluded
override. No defaults are injected, so the expansion logic sees the same
partial rules as before (35 tests still green).
Remaining: 7 react-hooks/exhaustive-deps warnings are left as-is — adding
the missing deps changes effect/memo timing and needs per-hook review, not
a mechanical fix. tsc --noEmit clean; eslint 0 errors / 7 warnings.
- Implemented Zustand store for S/MIME functionality, including state management for key records and public certificates.
- Added methods for importing PKCS#12 files and public certificates, binding identities to keys, and managing unlocked keys.
- Introduced session storage for remembering unlocked keys across sessions.
- Enhanced error handling and loading states during data operations.