feat: add self-registering provider factory (v0.2.0) - #7
Merged
Conversation
chore: propagate main into development
Register/New/RegisteredTypes at the module root, mirroring the database/sql self-registration idiom: Register panics on a nil factory or duplicate name (programmer error, caught at init time); New returns an error (never panics) for an unregistered provider type. Thread-safe via a sync.RWMutex-guarded map. This is the enabling mechanism for per-provider init()-based registration landing in follow-up commits.
StringField/StringSliceField extract plain string/[]string values out of a Factory's generic map[string]any config, tolerating missing or wrong-typed keys by returning the zero value rather than erroring — each provider's register.go decides which zero values are actually required. Avoids duplicating the same type-assert boilerplate across eight register.go files.
Each package gains an init()-time notify.Register("<name>", factory)
call in a new register.go, adapting the generic map[string]any config
into the package's typed Config via the shared regconfig helpers. The
existing typed New(cfg, wrapper) constructors are unchanged.
…egistry Same init()-time notify.Register pattern as discord/slack, adapted to each package's own Config fields (gotify/ntfy: url+token; pushover: user_key+api_token+base_url).
Same init()-time notify.Register pattern as the other providers, adapted to each package's own Config fields (telegram: bot_token+ chat_id+base_url; webhook: url).
Highest-design-risk registration: email.Config carries non-serializable Mailer/TemplateRenderer interfaces and a TemplateName closure, so its factory takes these directly out of the map[string]any config (under "mailer"/"renderer"/"template_name") rather than JSON-round-tripping plain data like the seven HTTP providers. "mailer" is the one required key; a missing or wrong-typed value returns an error, never a panic.
One-line "import _ .../providers/all" gets every built-in provider registered, for consumers that want zero-touch discovery over hand-picked imports. Includes a count-check test (asserting exactly 8 registered types) that acts as the CI safety net for the one step in adding a new provider with no compiler enforcement — forgetting to add it to this bundle.
- ARCHITECTURE.md (new): module layer overview, the Sender contract, a step-by-step "adding a new provider" guide (layout, Config/New conventions, the Register/factory template, providers/all wiring, naming/test conventions, error-handling conventions), registry internals, and a versioning note — precise enough for a human contributor or a coding agent to add a provider without guessing. - README.md: new "Provider registry" section covering notify.Register/ New, the providers/all quick-start, and a pointer to the fuller docs. - docs/INTEGRATION.md (new): Five Ws and One H guide for integrating this module into an unrelated project, with a full go-get-to-dispatch code walkthrough.
Adds the [0.2.0] entry documenting the provider registry addition, explaining why it's a minor bump despite being purely additive at the Go-API level (init()-time global registration side effect, panic-on-duplicate-name as a new failure mode). Also retroactively splits the prior catch-all "Unreleased" entry into a proper [0.1.0] section, since that content already shipped under the existing v0.1.0 tag and was never moved out of Unreleased.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a self-registering provider factory registry, mirroring
database/sql'sRegister/driver pattern, so new providers become discoverable by a consuming project without hand-edited switch statements.Each of the 8 existing providers (discord, slack, gotify, pushover, ntfy, webhook, telegram, email) now self-registers via
init(). A newproviders/allpackage blank-imports all of them for one-line full discovery. The existing typed constructors (discord.New(Config{...}, w)etc.) are unchanged and remain the primary, fully type-safe API — the registry is additive, not a replacement.This is a breaking/additive change to the public API introduced in
v0.1.0(new exported identifiers + init-time side effects), so it ships asv0.2.0.v0.1.0has not been adopted by anyone outside this project yet, so there's no compatibility concern.Why
map[string]anyoverjson.RawMessageemail.Configcarries non-serializable Go values (Mailer/TemplateRendererinterfaces, aTemplateNameclosure) that can never round-trip through JSON. A generic map keeps the registry usable for every provider, including that one.Docs
ARCHITECTURE.md(new): exactly how to add a new provider — package layout, theSendercontract, where theRegister/init()call goes,providers/allwiring, test conventions. Written for a human contributor or a coding agent to follow without guessing.docs/INTEGRATION.md(new): Five Ws and One H integration guide for adopting this module in a project other than Charon.[0.1.0](already shipped) and added[0.2.0]on top, so it's accurate going forward.Validation
go build/go vet/staticcheck: cleango test ./... -race: passinggithub.com/Wikid82/charon/*imports (grep-confirmed)goreleaser release --snapshot --cleandry-run: succeededDownstream
Charon's adoption of this registry (replacing its hardcoded provider-construction switch with
notify.New(...), while keeping its own explicit allowlist of which provider types it exposes) is in progress as part of Charon PR #1253, currently pinned to this branch via a localreplacedirective pending this merge + a real tagged release.🤖 Generated with Claude Code