Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
# @suaveplan/emailer - Universal email service with plugin transports (Dummy / SMTP via injectable SmtpClientLike / Gmail REST via FetchLike), nine lifecycle hooks, retry, queue dispatch, Zod-validated boundaries, OpenTelemetry-instrumented hot paths, injectable Clock/Rng/Logger/FetchLike/TimersLike, stable defineCodes('EMAILER', [...]) error registry.
Universal email service with pluggable transports. Ships
`EmailService`, three transports (Dummy / SMTP via injectable
`SmtpClientLike` / Gmail REST via injectable `FetchLike`), nine lifecycle
hooks, deterministic retry, structural queue dispatch, Zod-validated option
boundaries, OpenTelemetry-instrumented hot paths, and a stable
`defineCodes("EMAILER", [...])` error registry.
<!-- begin:auto-docs -->
## Documentation tree
- [email-service](./src/core/email-service/email-service.md) — `EmailService<TTransport>` is the public entry point for `@suaveplan/emailer`. It orchestrates message validation, life…
- [base-email-transport](./src/core/email-service/base-email-transport.md) — `BaseEmailTransport` is the abstract helper that every concrete transport (`DummyTransport`, `SmtpTransport`, `GmailRes…
- [email-service](./src/core/email-service/email-service.md) — `EmailService<TTransport>` is the public entry point for `@suaveplan/emailer`. It orchestrates message validation, life…
- [retry](./src/core/retry/retry.md) — Deterministic retry helper used by `EmailService.send`. The helper takes a `RetryPolicy`, an injectable `TimersLike`, a…
- [retry](./src/core/retry/retry.md) — Deterministic retry helper used by `EmailService.send`. The helper takes a `RetryPolicy`, an injectable `TimersLike`, a…
- [validate](./src/core/validate/validate.md) — Shared address-formatting and message-validation helpers used by every concrete transport and by `EmailService` itself.…
- [validate](./src/core/validate/validate.md) — Shared address-formatting and message-validation helpers used by every concrete transport and by `EmailService` itself.…
- [error-codes](./src/error-codes/error-codes.md) — `@suaveplan/emailer` ships a single stable error-code registry that every failure path in the package routes through. T…
- [error-codes](./src/error-codes/error-codes.md) — `@suaveplan/emailer` ships a single stable error-code registry that every failure path in the package routes through. T…
- [fake-fetch](./src/fakes/fake-fetch.md) — Deterministic test double for `FetchLike`, used by `GmailRestTransport` tests. Queues scripted responses and captures e…
- [fake-smtp-client](./src/fakes/fake-smtp-client.md) — Deterministic test double for `SmtpClientLike`. Tests queue scripted responses, invoke the wrapped `SmtpTransport`, and…
- [otel](./src/otel/metrics.md) — Single source of truth for every OpenTelemetry instrument emitted by `@suaveplan/emailer`. Every production path that t…
- [metrics](./src/otel/metrics.md) — Single source of truth for every OpenTelemetry instrument emitted by `@suaveplan/emailer`. Every production path that t…
- [schemas](./src/schemas/schemas.md) — Centralised Zod schemas for every public option bundle and wire payload in `@suaveplan/emailer`. The schemas exist to e…
- [schemas](./src/schemas/schemas.md) — Centralised Zod schemas for every public option bundle and wire payload in `@suaveplan/emailer`. The schemas exist to e…
- [dummy](./src/transports/dummy/dummy-transport.md) — `DummyTransport` is a deterministic in-memory transport designed for tests, fixtures, and local development. It records…
- [dummy-transport](./src/transports/dummy/dummy-transport.md) — `DummyTransport` is a deterministic in-memory transport designed for tests, fixtures, and local development. It records…
- [gmail-rest](./src/transports/gmail-rest/gmail-rest-transport.md) — `GmailRestTransport` sends mail through Gmail's REST API directly, over an injectable `FetchLike`. The transport builds…
- [gmail-rest-transport](./src/transports/gmail-rest/gmail-rest-transport.md) — `GmailRestTransport` sends mail through Gmail's REST API directly, over an injectable `FetchLike`. The transport builds…
- [smtp](./src/transports/smtp/smtp-transport.md) — `SmtpTransport` is a structural SMTP transport: it accepts a caller-supplied `SmtpClientLike` adapter (the contract is…
- [smtp-transport](./src/transports/smtp/smtp-transport.md) — `SmtpTransport` is a structural SMTP transport: it accepts a caller-supplied `SmtpClientLike` adapter (the contract is…
<!-- end:auto-docs -->
## Why universal
The upstream `@suaveplan/emailer` was server-only because it imported
`nodemailer` and `googleapis` directly. The rewrite drops both hard
dependencies in favour of injectable contracts:
- **SMTP**: callers supply a thin `SmtpClientLike` adapter so nodemailer
(or any other library) lives in the consumer's app shell, not in this
package.
- **Gmail**: send is implemented directly against the Gmail REST API via
`FetchLike`, so token acquisition is the caller's concern and the
transport runs unchanged in Bun, Node, and the browser.
## Modules
- [`src/core/email-service/email-service.md`](src/core/email-service/email-service.md) — `EmailService<TTransport>` orchestrator
- [`src/core/email-service/base-email-transport.md`](src/core/email-service/base-email-transport.md) — abstract helper
- [`src/core/retry/retry.md`](src/core/retry/retry.md) — deterministic retry helper
- [`src/core/validate/validate.md`](src/core/validate/validate.md) — address-formatting helpers
- [`src/transports/dummy/dummy-transport.md`](src/transports/dummy/dummy-transport.md) — in-memory test transport
- [`src/transports/smtp/smtp-transport.md`](src/transports/smtp/smtp-transport.md) — SMTP via adapter
- [`src/transports/smtp/smtp-client-like.types.md`](src/transports/smtp/smtp-client-like.types.md) — adapter contract
- [`src/transports/gmail-rest/gmail-rest-transport.md`](src/transports/gmail-rest/gmail-rest-transport.md) — Gmail REST transport
- [`src/error-codes.md`](src/error-codes.md) — error registry
- [`src/schemas/schemas.md`](src/schemas/schemas.md) — Zod boundary schemas
- [`src/types/emailer.types.md`](src/types/emailer.types.md) — public types
- [`src/otel/metrics.md`](src/otel/metrics.md) — OTel instruments
- [`src/fakes/fake-smtp-client.md`](src/fakes/fake-smtp-client.md) — deterministic SMTP fake
- [`src/fakes/fake-fetch.md`](src/fakes/fake-fetch.md) — deterministic fetch fake
## Quick start
```ts
import { EmailService } from "@suaveplan/emailer";
import { createDummyTransport } from "@suaveplan/emailer/transports/dummy";
const transport = createDummyTransport();
const service = new EmailService({
transport,
transportOptions: {},
defaultFrom: "no-reply@example.com",
});
await service.initialize();
const result = await service.send({
to: "user@example.com",
subject: "hello",
html: "<p>hi</p>",
});
```
## License
MIT