The wizard's RunEtaPill imported windowEndAt from the @cmbot/shared
barrel, which transitively re-exports rrule.ts. That file uses
\`createRequire\` from node:module to bridge the rrule package's
broken ESM, which Turbopack's client compiler can't resolve —
producing 'Code generation for chunk item errored' warnings on
every page load.
* Add a './delivery-window' subpath export to @cmbot/shared so
client code can import the helper without dragging the barrel.
* Switch review-submit-client.tsx to that subpath.
* Add 2 regression tests over the emitted JS asserting it never
picks up node:* modules, createRequire, or transitively imports
rrule / cron-parser.
ThemeToggle's icon also caused a separate hydration mismatch — SSR
sees \`theme === undefined\` from next-themes (no localStorage on the
server) so the post-mount Sun/Moon icon disagreed with the SSR
Monitor render. Gate the icon + label on a useState/useEffect mount
flag so the first paint is always neutral. Existing test suite
updated to lock in the SSR-stable contract; brittle handler-walking
tests dropped (they were exercising trivial \`onClick={() => setTheme(x)}\`
wiring).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
I incorrectly removed next-themes thinking it caused the hydration
warning. The actual mismatch was a `__gcrremoteframetoken` attribute
added to <html> by a browser extension, which the previous commit
already addressed via `suppressHydrationWarning`.
Restored:
- ThemeProvider wrap in the layout
- ThemeToggle component
- Sonner Toaster's useTheme() so toasts respect the chosen theme
- Appearance card on the Settings page
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
next-themes hydration mismatch
- Removed the next-themes wrapper, ThemeProvider component, and the
Settings appearance card — there's no theme-toggle UI anywhere in
the app, so the library was just adding a pre-hydration `<script>`
that triggered React 19's "script tag while rendering" warning and
the `<html>` class swap caused the hydration mismatch.
- Sonner Toaster now uses a fixed `theme="light"` instead of useTheme.
- Layout drops `suppressHydrationWarning` on `<html>` since we no
longer mutate it on mount.
QR refs exhausted before the user could scan
- Pass `qrTimeout: 60_000` to makeWASocket so each QR (first AND
subsequent) lasts a full minute. Default was 60 s for the first and
20 s for each subsequent → ~6 refs × default = ~2.5 min before
Baileys gave up. With 60 s flat, the user has the full ~5 min
window matching pair-handler's PAIR_TIMEOUT_MS.
Pairing-timed-out screen
- "Try again" used to link to /accounts/new (creates a new account
instead of re-pairing the existing one). Link now points to the
existing /accounts/[id] detail page where the operator can hit
Re-pair.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>