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,85 @@
# parser
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Wraps `postal-mime` with a strict input/option boundary, OTel
instrumentation, structured error codes, and the
`@suaveplan/email-processing/hooks` pipeline. `parseEmail` is the
package's primary entry point: it takes a raw RFC 822 message in any
of the three supported input shapes (string, `ArrayBuffer`,
`Uint8Array`) and returns a fully-parsed `ParsedEmail` whose
attachments are real MIME parts (no stubs).
## Features
- Three input modes — string, `ArrayBuffer`, `Uint8Array` — covering
both browser and Node consumers.
- Zod-validated options at the boundary, raising
`EMAIL_PROCESSING.INVALID_OPTIONS` with the failing issues on
`context` so callers can surface diagnostics.
- Distinct error codes for `INVALID_INPUT` (null/undefined/wrong type)
and `PARSE_FAILURE` (`postal-mime` threw); `parse.failure_total`
is incremented for the latter.
- Hook pipeline integration — every parse returns the result of
`emailHooks.applyHooksAsync("email:processing", …)`.
- `parseEmailAddress` and `decodeEmailWords` re-export the
`postal-mime` low-level helpers under the package's typed surface,
with the same `INVALID_INPUT` guard.
## Usage: Basic
```ts
import { parseEmail } from "@suaveplan/email-processing/parser";
const parsed = await parseEmail(rawMimeString);
console.log(parsed.subject, parsed.attachments.length);
```
## Usage: Advanced
```ts
import { parseEmail } from "@suaveplan/email-processing/parser";
import { onEmailProcessing } from "@suaveplan/email-processing/hooks";
const off = onEmailProcessing((data) => ({
...data,
parsed: {
...data.parsed,
html: data.parsed.html?.replace(/<script[\s\S]*?<\/script>/gi, ""),
},
}));
try {
const parsed = await parseEmail(buffer, {
attachmentEncoding: "base64",
maxNestingDepth: 64,
});
await persist(parsed);
} finally {
off();
}
```
## API Reference
- `parseEmail(raw, options?)` — async; returns `ParsedEmail`. Throws
`EmailProcessingError` with codes `INVALID_INPUT`,
`INVALID_OPTIONS`, or `PARSE_FAILURE`.
- `parseEmailAddress(addressString)` — sync; returns `EmailAddress[]`.
Throws `EmailProcessingError(INVALID_INPUT)` for non-string input.
- `decodeEmailWords(text)` — sync; returns decoded RFC 2047 string.
Throws `EmailProcessingError(INVALID_INPUT)` for non-string input.
## Implementation Notes
`parseEmail` records `email_processing.parse.total` with the attachment
count as an attribute so dashboards can surface average
attachments-per-message. Parse failures increment a separate
`parse.failure_total` counter (no attachment count is recorded because
the parser never reached the attachment array). The Zod options schema
is `.strict()` so unknown option keys are rejected — this catches
typos at the boundary instead of letting them silently no-op.