Repository: favonia/cloudflare-ddns
Pull request #916 (2024-08-31 17:42:32)

docs: various tweaks

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/916?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 95.58%. Comparing base [(`06a5bd9`)](https://app.codecov.io/gh/favonia/cloudflare-ddns/commit/06a5bd9bc0fd40f999fe6db7a1ad4d720a1e22ea?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) to head [(`e4ebff5`)](https://app.codecov.io/gh/favonia/cloudflare-ddns/commit/e4ebff5adf144ad500174985371eecf115cabd01?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main     #916   +/-   ##
=======================================
  Coverage   95.58%   95.58%           
=======================================
  Files          58       58           
  Lines        2583     2583           
=======================================
  Hits         2469     2469           
  Misses        104      104           
  Partials       10       10           
```

| [Flag](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/916/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/916/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) | `95.58% <100.00%> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/916?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).


Patch:
diff --git a/README.markdown b/README.markdown
index 0cc3200..5848804 100644
--- a/README.markdown
+++ b/README.markdown
@@ -274,7 +274,7 @@ _(Click to expand the following items.)_
 > 🤖 Technical notes on WAF lists:
 >
 > 1. [Cloudflare does not allow single IPv6 addresses in a WAF list](https://developers.cloudflare.com/waf/tools/lists/custom-lists/#lists-with-ip-addresses-ip-lists), and thus the updater will use the smallest IP range allowed by Cloudflare that contains the detected IPv6 address.
-> 2. The updater will delete unmanaged IPs from the specified WAF lists (e.g., if you disable IPv6 with `IP6_PROVIDER=none`, then existing IPv6 addresses or IPv6 ranges in the lists will be deleted). The idea is that the list should only contain detected IP addresses.
+> 2. The updater will delete IP addresses belonging to unmanaged IP families from the specified WAF lists (_e.g.,_ if you disable IPv6 with `IP6_PROVIDER=none`, then existing IPv6 addresses or IPv6 ranges in the lists will be deleted). The idea is that the list should contain only detected IP addresses.
 
 </details>
 
diff --git a/internal/domainexp/parser.go b/internal/domainexp/parser.go
index eae6725..1641bec 100644
--- a/internal/domainexp/parser.go
+++ b/internal/domainexp/parser.go
@@ -91,9 +91,7 @@ func hasStrictSuffix(s, suffix string) bool {
 
 // scanFactor mimics ParseBool, call scanFunction, and then check parenthesized expressions.
 //
-// <factor> --> true | false | <fun> | ! <factor> | ( <expression> )
-//
-
+//	<factor> --> true | false | <fun> | ! <factor> | ( <expression> )
 func scanFactor(ppfmt pp.PP, key string, input string, tokens []string) (predicate, []string) {
 	// fmt.Printf("scanFactor(tokens = %#v)\n", tokens)
 
diff --git a/internal/message/message.go b/internal/message/message.go
deleted file mode 100644
index 61e63f2..0000000
--- a/internal/message/message.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Package message defines the structures holding messages for
-// monitors and notifiers.
-package message
-
-import (
-	"github.com/favonia/cloudflare-ddns/internal/monitor"
-	"github.com/favonia/cloudflare-ddns/internal/notifier"
-)
-
-// Message encapsulates the messages to both monitiors and notifiers.
-type Message struct {
-	MonitorMessage  monitor.Message
-	NotifierMessage notifier.Message
-}
-
-// New creates a new, empty message.
-func New() Message {
-	return Message{
-		MonitorMessage:  monitor.NewMessage(),
-		NotifierMessage: notifier.NewMessage(),
-	}
-}
-
-// Merge combines multiple compound messages.
-func Merge(msgs ...Message) Message {
-	mms := make([]monitor.Message, len(msgs))
-	nms := make([]notifier.Message, len(msgs))
-
-	for i := range msgs {
-		mms[i] = msgs[i].MonitorMessage
-		nms[i] = msgs[i].NotifierMessage
-	}
-
-	return Message{
-		MonitorMessage:  monitor.MergeMessages(mms...),
-		NotifierMessage: notifier.MergeMessages(nms...),
-	}
-}
diff --git a/internal/updater/message.go b/internal/updater/message.go
index 19cbbc0..120598f 100644
--- a/internal/updater/message.go
+++ b/internal/updater/message.go
@@ -1,198 +1,36 @@
 package updater
 
 import (
-	"fmt"
-	"net/netip"
-	"strings"
-
-	"github.com/favonia/cloudflare-ddns/internal/domain"
-	"github.com/favonia/cloudflare-ddns/internal/ipnet"
-	"github.com/favonia/cloudflare-ddns/internal/message"
 	"github.com/favonia/cloudflare-ddns/internal/monitor"
 	"github.com/favonia/cloudflare-ddns/internal/notifier"
-	"github.com/favonia/cloudflare-ddns/internal/pp"
-	"github.com/favonia/cloudflare-ddns/internal/setter"
 )
 
-type setterResponses map[setter.ResponseCode][]string
-
-func emptySetterResponses() setterResponses {
-	return setterResponses{}
-}
-
-func (s setterResponses) register(d domain.Domain, code setter.ResponseCode) {
-	s[code] = append(s[code], d.Describe())
-}
-
-func generateDetectMessage(ipNet ipnet.Type, ok bool) message.Message {
-	switch {
-	default:
-		return message.New()
-	case !ok:
-		return message.Message{
-			MonitorMessage: monitor.Message{
-				OK:    false,
-				Lines: []string{fmt.Sprintf("Failed to detect %s address", ipNet.Describe())},
-			},
-			NotifierMessage: notifier.Message{
-				fmt.Sprintf("Failed to detect the %s address.", ipNet.Describe()),
-			},
-		}
-	}
-}
-
-func generateUpdateMonitorMessage(ipNet ipnet.Type, ip netip.Addr, s setterResponses) monitor.Message {
-	if domains := s[setter.ResponseFailed]; len(domains) > 0 {
-		return monitor.Message{
-			OK: false,
-			Lines: []string{fmt.Sprintf(
-				"Failed to set %s (%s) of %s",
-				ipNet.RecordType(), ip.String(), pp.Join(domains),
-			)},
-		}
-	}
-
-	var successLines []string
-
-	if domains := s[setter.ResponseUpdating]; len(domains) > 0 {
-		successLines = append(successLines, fmt.Sprintf(
-			"Setting %s (%s) of %s",
-			ipNet.RecordType(), ip.String(), pp.Join(domains),
-		))
-	}
-
-	if domains := s[setter.ResponseUpdated]; len(domains) > 0 {
-		successLines = append(successLines, fmt.Sprintf(
-			"Set %s (%s) of %s",
-			ipNet.RecordType(), ip.String(), pp.Join(domains),
-		))
-	}
-
-	return monitor.Message{OK: true, Lines: successLines}
-}
-
-func generateUpdateNotifierMessage(ipNet ipnet.Type, ip netip.Addr, s setterResponses) notifier.Message {
-	var fragments []string
-
-	if domains := s[setter.ResponseFailed]; len(domains) > 0 {
-		fragments = append(fragments,
-			"Failed to properly update ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains), " with ", ip.String(),
-		)
-	}
-
-	if domains := s[setter.ResponseUpdating]; len(domains) > 0 {
-		if len(fragments) == 0 {
-			fragments = append(fragments,
-				"Updating ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains), " with ", ip.String(),
-			)
-		} else {
-			fragments = append(fragments,
-				"; updating those of ", pp.EnglishJoin(domains),
-			)
-		}
-	}
-
-	if domains := s[setter.ResponseUpdated]; len(domains) > 0 {
-		if len(fragments) == 0 {
-			fragments = append(fragments,
-				"Updated ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains), " with ", ip.String(),
-			)
-		} else {
-			fragments = append(fragments,
-				"; updated those of ", pp.EnglishJoin(domains),
-			)
-		}
-	}
-
-	if len(fragments) == 0 {
-		return nil
-	} else {
-		fragments = append(fragments, ".")
-		return notifier.Message{strings.Join(fragments, "")}
-	}
+// Message encapsulates the messages to both monitiors and notifiers.
+type Message struct {
+	MonitorMessage  monitor.Message
+	NotifierMessage notifier.Message
 }
 
-func generateUpdateMessage(ipNet ipnet.Type, ip netip.Addr, s setterResponses) message.Message {
-	return message.Message{
-		MonitorMessage:  generateUpdateMonitorMessage(ipNet, ip, s),
-		NotifierMessage: generateUpdateNotifierMessage(ipNet, ip, s),
+// NewMessage creates a new, empty message.
+func NewMessage() Message {
+	return Message{
+		MonitorMessage:  monitor.NewMessage(),
+		NotifierMessage: notifier.NewMessage(),
 	}
 }
 
-func generateDeleteMonitorMessage(ipNet ipnet.Type, s setterResponses) monitor.Message {
-	if domains := s[setter.ResponseFailed]; len(domains) > 0 {
-		return monitor.Message{
-			OK: false,
-			Lines: []string{fmt.Sprintf(
-				"Failed to delete %s of %s",
-				ipNet.RecordType(), pp.Join(domains),
-			)},
-		}
-	}
+// MergeMessages combines multiple compound messages.
+func MergeMessages(msgs ...Message) Message {
+	mms := make([]monitor.Message, len(msgs))
+	nms := make([]notifier.Message, len(msgs))
 
-	var successLines []string
-
-	if domains := s[setter.ResponseUpdating]; len(domains) > 0 {
-		successLines = append(successLines, fmt.Sprintf(
-			"Deleting %s of %s",
-			ipNet.RecordType(), pp.Join(domains),
-		))
-	}
-
-	if domains := s[setter.ResponseUpdated]; len(domains) > 0 {
-		successLines = append(successLines, fmt.Sprintf(
-			"Deleted %s of %s",
-			ipNet.RecordType(), pp.Join(domains),
-		))
+	for i := range msgs {
+		mms[i] = msgs[i].MonitorMessage
+		nms[i] = msgs[i].NotifierMessage
 	}
 
-	return monitor.Message{OK: true, Lines: successLines}
-}
-
-func generateDeleteNotifierMessage(ipNet ipnet.Type, s setterResponses) notifier.Message {
-	var fragments []string
-
-	if domains := s[setter.ResponseFailed]; len(domains) > 0 {
-		fragments = append(fragments,
-			"Failed to properly delete ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains),
-		)
-	}
-
-	if domains := s[setter.ResponseUpdating]; len(domains) > 0 {
-		if len(fragments) == 0 {
-			fragments = append(fragments,
-				"Deleting ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains),
-			)
-		} else {
-			fragments = append(fragments,
-				"; deleting those of ", pp.EnglishJoin(domains),
-			)
-		}
-	}
-
-	if domains := s[setter.ResponseUpdated]; len(domains) > 0 {
-		if len(fragments) == 0 {
-			fragments = append(fragments,
-				"Deleted ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains),
-			)
-		} else {
-			fragments = append(fragments,
-				"; deleted those of ", pp.EnglishJoin(domains),
-			)
-		}
-	}
-
-	if len(fragments) == 0 {
-		return nil
-	} else {
-		fragments = append(fragments, ".")
-		return notifier.Message{strings.Join(fragments, "")}
-	}
-}
-
-func generateDeleteMessage(ipNet ipnet.Type, s setterResponses) message.Message {
-	return message.Message{
-		MonitorMessage:  generateDeleteMonitorMessage(ipNet, s),
-		NotifierMessage: generateDeleteNotifierMessage(ipNet, s),
+	return Message{
+		MonitorMessage:  monitor.MergeMessages(mms...),
+		NotifierMessage: notifier.MergeMessages(nms...),
 	}
 }
diff --git a/internal/updater/message_records.go b/internal/updater/message_records.go
new file mode 100644
index 0000000..92de4b0
--- /dev/null
+++ b/internal/updater/message_records.go
@@ -0,0 +1,197 @@
+package updater
+
+import (
+	"fmt"
+	"net/netip"
+	"strings"
+
+	"github.com/favonia/cloudflare-ddns/internal/domain"
+	"github.com/favonia/cloudflare-ddns/internal/ipnet"
+	"github.com/favonia/cloudflare-ddns/internal/monitor"
+	"github.com/favonia/cloudflare-ddns/internal/notifier"
+	"github.com/favonia/cloudflare-ddns/internal/pp"
+	"github.com/favonia/cloudflare-ddns/internal/setter"
+)
+
+type setterResponses map[setter.ResponseCode][]string
+
+func emptySetterResponses() setterResponses {
+	return setterResponses{}
+}
+
+func (s setterResponses) register(d domain.Domain, code setter.ResponseCode) {
+	s[code] = append(s[code], d.Describe())
+}
+
+func generateDetectMessage(ipNet ipnet.Type, ok bool) Message {
+	switch {
+	default:
+		return NewMessage()
+	case !ok:
+		return Message{
+			MonitorMessage: monitor.Message{
+				OK:    false,
+				Lines: []string{fmt.Sprintf("Failed to detect %s address", ipNet.Describe())},
+			},
+			NotifierMessage: notifier.Message{
+				fmt.Sprintf("Failed to detect the %s address.", ipNet.Describe()),
+			},
+		}
+	}
+}
+
+func generateUpdateMonitorMessage(ipNet ipnet.Type, ip netip.Addr, s setterResponses) monitor.Message {
+	if domains := s[setter.ResponseFailed]; len(domains) > 0 {
+		return monitor.Message{
+			OK: false,
+			Lines: []string{fmt.Sprintf(
+				"Failed to set %s (%s) of %s",
+				ipNet.RecordType(), ip.String(), pp.Join(domains),
+			)},
+		}
+	}
+
+	var successLines []string
+
+	if domains := s[setter.ResponseUpdating]; len(domains) > 0 {
+		successLines = append(successLines, fmt.Sprintf(
+			"Setting %s (%s) of %s",
+			ipNet.RecordType(), ip.String(), pp.Join(domains),
+		))
+	}
+
+	if domains := s[setter.ResponseUpdated]; len(domains) > 0 {
+		successLines = append(successLines, fmt.Sprintf(
+			"Set %s (%s) of %s",
+			ipNet.RecordType(), ip.String(), pp.Join(domains),
+		))
+	}
+
+	return monitor.Message{OK: true, Lines: successLines}
+}
+
+func generateUpdateNotifierMessage(ipNet ipnet.Type, ip netip.Addr, s setterResponses) notifier.Message {
+	var fragments []string
+
+	if domains := s[setter.ResponseFailed]; len(domains) > 0 {
+		fragments = append(fragments,
+			"Failed to properly update ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains), " with ", ip.String(),
+		)
+	}
+
+	if domains := s[setter.ResponseUpdating]; len(domains) > 0 {
+		if len(fragments) == 0 {
+			fragments = append(fragments,
+				"Updating ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains), " with ", ip.String(),
+			)
+		} else {
+			fragments = append(fragments,
+				"; updating those of ", pp.EnglishJoin(domains),
+			)
+		}
+	}
+
+	if domains := s[setter.ResponseUpdated]; len(domains) > 0 {
+		if len(fragments) == 0 {
+			fragments = append(fragments,
+				"Updated ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains), " with ", ip.String(),
+			)
+		} else {
+			fragments = append(fragments,
+				"; updated those of ", pp.EnglishJoin(domains),
+			)
+		}
+	}
+
+	if len(fragments) == 0 {
+		return nil
+	} else {
+		fragments = append(fragments, ".")
+		return notifier.Message{strings.Join(fragments, "")}
+	}
+}
+
+func generateUpdateMessage(ipNet ipnet.Type, ip netip.Addr, s setterResponses) Message {
+	return Message{
+		MonitorMessage:  generateUpdateMonitorMessage(ipNet, ip, s),
+		NotifierMessage: generateUpdateNotifierMessage(ipNet, ip, s),
+	}
+}
+
+func generateDeleteMonitorMessage(ipNet ipnet.Type, s setterResponses) monitor.Message {
+	if domains := s[setter.ResponseFailed]; len(domains) > 0 {
+		return monitor.Message{
+			OK: false,
+			Lines: []string{fmt.Sprintf(
+				"Failed to delete %s of %s",
+				ipNet.RecordType(), pp.Join(domains),
+			)},
+		}
+	}
+
+	var successLines []string
+
+	if domains := s[setter.ResponseUpdating]; len(domains) > 0 {
+		successLines = append(successLines, fmt.Sprintf(
+			"Deleting %s of %s",
+			ipNet.RecordType(), pp.Join(domains),
+		))
+	}
+
+	if domains := s[setter.ResponseUpdated]; len(domains) > 0 {
+		successLines = append(successLines, fmt.Sprintf(
+			"Deleted %s of %s",
+			ipNet.RecordType(), pp.Join(domains),
+		))
+	}
+
+	return monitor.Message{OK: true, Lines: successLines}
+}
+
+func generateDeleteNotifierMessage(ipNet ipnet.Type, s setterResponses) notifier.Message {
+	var fragments []string
+
+	if domains := s[setter.ResponseFailed]; len(domains) > 0 {
+		fragments = append(fragments,
+			"Failed to properly delete ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains),
+		)
+	}
+
+	if domains := s[setter.ResponseUpdating]; len(domains) > 0 {
+		if len(fragments) == 0 {
+			fragments = append(fragments,
+				"Deleting ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains),
+			)
+		} else {
+			fragments = append(fragments,
+				"; deleting those of ", pp.EnglishJoin(domains),
+			)
+		}
+	}
+
+	if domains := s[setter.ResponseUpdated]; len(domains) > 0 {
+		if len(fragments) == 0 {
+			fragments = append(fragments,
+				"Deleted ", ipNet.RecordType(), " records of ", pp.EnglishJoin(domains),
+			)
+		} else {
+			fragments = append(fragments,
+				"; deleted those of ", pp.EnglishJoin(domains),
+			)
+		}
+	}
+
+	if len(fragments) == 0 {
+		return nil
+	} else {
+		fragments = append(fragments, ".")
+		return notifier.Message{strings.Join(fragments, "")}
+	}
+}
+
+func generateDeleteMessage(ipNet ipnet.Type, s setterResponses) Message {
+	return Message{
+		MonitorMessage:  generateDeleteMonitorMessage(ipNet, s),
+		NotifierMessage: generateDeleteNotifierMessage(ipNet, s),
+	}
+}
diff --git a/internal/updater/message_waf.go b/internal/updater/message_waf.go
index 1808137..cfe95dc 100644
--- a/internal/updater/message_waf.go
+++ b/internal/updater/message_waf.go
@@ -3,7 +3,6 @@ package updater
 import (
 	"strings"
 
-	"github.com/favonia/cloudflare-ddns/internal/message"
 	"github.com/favonia/cloudflare-ddns/internal/monitor"
 	"github.com/favonia/cloudflare-ddns/internal/notifier"
 	"github.com/favonia/cloudflare-ddns/internal/pp"
@@ -72,8 +71,8 @@ func generateUpdateWAFListsNotifierMessage(s setterWAFListResponses) notifier.Me
 	}
 }
 
-func generateUpdateWAFListsMessage(s setterWAFListResponses) message.Message {
-	return message.Message{
+func generateUpdateWAFListsMessage(s setterWAFListResponses) Message {
+	return Message{
 		MonitorMessage:  generateUpdateWAFListsMonitorMessage(s),
 		NotifierMessage: generateUpdateWAFListsNotifierMessage(s),
 	}
@@ -131,8 +130,8 @@ func generateClearWAFListsNotifierMessage(s setterWAFListResponses) notifier.Mes
 	}
 }
 
-func generateClearWAFListsMessage(s setterWAFListResponses) message.Message {
-	return message.Message{
+func generateClearWAFListsMessage(s setterWAFListResponses) Message {
+	return Message{
 		MonitorMessage:  generateClearWAFListsMonitorMessage(s),
 		NotifierMessage: generateClearWAFListsNotifierMessage(s),
 	}
diff --git a/internal/updater/updater.go b/internal/updater/updater.go
index c2c4471..27dfa72 100644
--- a/internal/updater/updater.go
+++ b/internal/updater/updater.go
@@ -9,7 +9,6 @@ import (
 
 	"github.com/favonia/cloudflare-ddns/internal/config"
 	"github.com/favonia/cloudflare-ddns/internal/ipnet"
-	"github.com/favonia/cloudflare-ddns/internal/message"
 	"github.com/favonia/cloudflare-ddns/internal/pp"
 	"github.com/favonia/cloudflare-ddns/internal/provider"
 	"github.com/favonia/cloudflare-ddns/internal/provider/protocol"
@@ -23,7 +22,7 @@ func getHintIDForDetection(ipNet ipnet.Type) pp.Hint {
 	}[ipNet]
 }
 
-func detectIP(ctx context.Context, ppfmt pp.PP, c *config.Config, ipNet ipnet.Type) (netip.Addr, message.Message) {
+func detectIP(ctx context.Context, ppfmt pp.PP, c *config.Config, ipNet ipnet.Type) (netip.Addr, Message) {
 	ctx, cancel := context.WithTimeoutCause(ctx, c.DetectionTimeout, errTimeout)
 	defer cancel()
 
@@ -87,7 +86,7 @@ func wrapUpdateWithTimeout(ctx context.Context, ppfmt pp.PP, c *config.Config,
 // ip must be non-zero.
 func setIP(ctx context.Context, ppfmt pp.PP,
 	c *config.Config, s setter.Setter, ipNet ipnet.Type, ip netip.Addr,
-) message.Message {
+) Message {
 	resps := emptySetterResponses()
 
 	for _, domain := range c.Domains[ipNet] {
@@ -102,7 +101,7 @@ func setIP(ctx context.Context, ppfmt pp.PP,
 }
 
 // deleteIP extracts relevant settings from the configuration and calls [setter.Setter.Delete] with a deadline.
-func deleteIP(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter, ipNet ipnet.Type) message.Message {
+func deleteIP(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter, ipNet ipnet.Type) Message {
 	resps := emptySetterResponses()
 
 	for _, domain := range c.Domains[ipNet] {
@@ -119,7 +118,7 @@ func deleteIP(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Sette
 // setWAFList extracts relevant settings from the configuration and calls [setter.Setter.SetWAFList] with timeout.
 func setWAFLists(ctx context.Context, ppfmt pp.PP,
 	c *config.Config, s setter.Setter, detectedIP map[ipnet.Type]netip.Addr,
-) message.Message {
+) Message {
 	resps := emptySetterWAFListResponses()
 
 	for _, l := range c.WAFLists {
@@ -135,7 +134,7 @@ func setWAFLists(ctx context.Context, ppfmt pp.PP,
 
 // clearWAFLists extracts relevant settings from the configuration
 // and calls [setter.Setter.ClearWAFList] with a deadline.
-func clearWAFLists(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter) message.Message {
+func clearWAFLists(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter) Message {
 	resps := emptySetterWAFListResponses()
 
 	for _, l := range c.WAFLists {
@@ -150,8 +149,8 @@ func clearWAFLists(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.
 }
 
 // UpdateIPs detect IP addresses and update DNS records of managed domains.
-func UpdateIPs(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter) message.Message {
-	var msgs []message.Message
+func UpdateIPs(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter) Message {
+	var msgs []Message
 	detectedIP := map[ipnet.Type]netip.Addr{}
 	numManagedNetworks := 0
 	numValidIPs := 0
@@ -176,12 +175,12 @@ func UpdateIPs(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Sett
 		msgs = append(msgs, setWAFLists(ctx, ppfmt, c, s, detectedIP))
 	}
 
-	return message.Merge(msgs...)
+	return MergeMessages(msgs...)
 }
 
 // DeleteIPs removes all DNS records of managed domains.
-func DeleteIPs(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter) message.Message {
-	var msgs []message.Message
+func DeleteIPs(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter) Message {
+	var msgs []Message
 
 	for ipNet, provider := range ipnet.Bindings(c.Provider) {
 		if provider != nil {
@@ -192,5 +191,5 @@ func DeleteIPs(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Sett
 	// Clear WAF lists
 	msgs = append(msgs, clearWAFLists(ctx, ppfmt, c, s))
 
-	return message.Merge(msgs...)
+	return MergeMessages(msgs...)
 }


Test patch:
diff --git a/internal/updater/updater_test.go b/internal/updater/updater_test.go
index b56480c..7b7bc84 100644
--- a/internal/updater/updater_test.go
+++ b/internal/updater/updater_test.go
@@ -13,7 +13,6 @@ import (
 	"github.com/favonia/cloudflare-ddns/internal/config"
 	"github.com/favonia/cloudflare-ddns/internal/domain"
 	"github.com/favonia/cloudflare-ddns/internal/ipnet"
-	"github.com/favonia/cloudflare-ddns/internal/message"
 	"github.com/favonia/cloudflare-ddns/internal/mocks"
 	"github.com/favonia/cloudflare-ddns/internal/monitor"
 	"github.com/favonia/cloudflare-ddns/internal/notifier"
@@ -178,7 +177,7 @@ func TestUpdateIPsMultiple(t *testing.T) {
 			}
 
 			resp := updater.UpdateIPs(ctx, mockPP, conf, mockSetter)
-			require.Equal(t, message.Message{
+			require.Equal(t, updater.Message{
 				MonitorMessage: monitor.Message{
 					OK:    tc.ok,
 					Lines: tc.monitorMessages,
@@ -279,7 +278,7 @@ func TestDeleteIPsMultiple(t *testing.T) {
 				tc.prepareMocks(mockPP, mockSetter)
 			}
 			resp := updater.DeleteIPs(ctx, mockPP, conf, mockSetter)
-			require.Equal(t, message.Message{
+			require.Equal(t, updater.Message{
 				MonitorMessage: monitor.Message{
 					OK:    tc.ok,
 					Lines: tc.monitorMessages,
@@ -650,7 +649,7 @@ func TestUpdateIPs(t *testing.T) {
 				tc.prepareMocks(mockPP, mockProviders, mockSetter)
 			}
 			resp := updater.UpdateIPs(ctx, mockPP, conf, mockSetter)
-			require.Equal(t, message.Message{
+			require.Equal(t, updater.Message{
 				MonitorMessage: monitor.Message{
 					OK:    tc.ok,
 					Lines: tc.monitorMessages,
@@ -875,7 +874,7 @@ func TestDeleteIPs(t *testing.T) {
 			}
 
 			resp := updater.DeleteIPs(ctx, mockPP, conf, mockSetter)
-			require.Equal(t, message.Message{
+			require.Equal(t, updater.Message{
 				MonitorMessage: monitor.Message{
 					OK:    tc.ok,
 					Lines: tc.monitorMessages,