v0.14.3
28 September 2026 Latest- Signing secret on by default. Without
signingSecreta random per-install secret is generated once at boot and stored inhulo_licence_store(keyvendure-plugin-email-tracking:signing-secret; first writer wins so server and worker sign and verify alike), then applied as if configured. Bare-id links in already-sent emails behave exactly as in 0.14.2 (pixel served, clicks to own hosts only). A boot warning explains that settingsigningSecretkeeps links valid across reinstalls. A generated secret is never used to authenticate the bounce webhook. - Per-link tokens are live.
/email-track/click/:tokenaccepts the 64-hex tokens minted byEmailLinkService.issueLinkToken()(?u=…&s=…): the row must exist and be unexpired, and both the HMAC and the stored destination hash must match, so the token binds its URL. Sensitive links are recorded by their redacted form.EmailLinkServicesigns with the env override, else the plugin'ssigningSecret. - Postgres corpus test (
src/pg-corpus.test.ts, runs whenHULO_PG_URLis set): every raw SQL statement insrc/is translated by the dialect adapter and executed against PostgreSQL 17 with TypeORM-quoted stand-ins.
- Bounces could not be matched to pipeline mail.
TrackingEmailSenderdelegated toNodemailerEmailSender, which discards nodemailer's result, so rows for order confirmations, OTPs and password resets never had asmtpMessageId/smtpResponse. ACapturingSendersubclass keeps the result per send; the row now gets the Message-ID (stored without angle brackets, also forsendTracked) and the SMTP reply, and its status is set from the reply code likesendTrackeddoes.
- Retention is now plugin-side: it runs daily on the worker only, deletes
email_login batches of 5 000 (oldest id first, short pause between batches) instead of one unbounded statement, appliesmaxRowsthe same way, and prunesemail_linkrows pastexpiresAtor older thandays. - Tests are no longer compiled into
dist.