Initial Commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# mime-utils
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Wraps the `libmime` library with a strict, typed boundary so the rest
|
||||
of the package can call RFC 2047 / 2231 / 5322 encoding and decoding
|
||||
helpers without using `// @ts-expect-error` or leaking `any` through
|
||||
the consumer surface. Every helper validates its primary string
|
||||
argument and raises an `EmailProcessingError` with code
|
||||
`EMAIL_PROCESSING.INVALID_INPUT` rather than silently calling `libmime`
|
||||
with garbage.
|
||||
|
||||
## Features
|
||||
|
||||
- Eleven wrappers: `encodeWord` / `encodeWords` / `decodeWords`,
|
||||
`decodeHeader` / `decodeHeaders`, `parseHeaderValue` /
|
||||
`buildHeaderValue` / `buildHeaderParam`, `foldLines`,
|
||||
`encodeFlowed` / `decodeFlowed`.
|
||||
- Local ambient declaration (`libmime.d.ts`) so the package compiles
|
||||
without `@types/libmime` while keeping the inner types narrow.
|
||||
- Strict input validation at every entry point — non-string args
|
||||
raise `INVALID_INPUT`, which is testable and observable.
|
||||
- Pass-through of optional parameters such as `maxLength`,
|
||||
`lineLength`, `afterSpace`, `delSp` so callers retain full
|
||||
`libmime` flexibility.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { encodeWord, decodeWords } from "@suaveplan/email-processing/mime-utils";
|
||||
|
||||
const encoded = encodeWord("résumé", "Q");
|
||||
const original = decodeWords(encoded);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
parseHeaderValue,
|
||||
buildHeaderValue,
|
||||
buildHeaderParam,
|
||||
foldLines,
|
||||
} from "@suaveplan/email-processing/mime-utils";
|
||||
|
||||
const parsed = parseHeaderValue('text/plain; charset="utf-8"; name="r.txt"');
|
||||
const segments = buildHeaderParam("filename*", "réport-2024.pdf", 60);
|
||||
parsed.params.filename = segments.map((s) => s.value).join("");
|
||||
|
||||
const header = foldLines(
|
||||
`Content-Type: ${buildHeaderValue(parsed)}`,
|
||||
76,
|
||||
true
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `encodeWord(str, encoding?, maxLength?)`
|
||||
- `encodeWords(str, encoding?, maxLength?)`
|
||||
- `decodeWords(str)`
|
||||
- `decodeHeader(headerLine)` → `{ key, value }`
|
||||
- `decodeHeaders(headers)` → `Record<string, string[]>`
|
||||
- `parseHeaderValue(valueString)` → `StructuredHeaderValue`
|
||||
- `buildHeaderValue(structured)` → `string`
|
||||
- `buildHeaderParam(key, value, maxLength?)` → `HeaderParam[]`
|
||||
- `foldLines(str, lineLength?, afterSpace?)`
|
||||
- `encodeFlowed(str, lineLength?)`
|
||||
- `decodeFlowed(str, delSp?)`
|
||||
|
||||
All throw `EmailProcessingError` with code
|
||||
`EMAIL_PROCESSING.INVALID_INPUT` when their primary argument is missing
|
||||
or of the wrong type.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`libmime` ships without TypeScript declarations, so this module owns a
|
||||
local `libmime.d.ts` declaring only the subset of functions in use.
|
||||
That keeps the package compatible with strict `verbatimModuleSyntax`
|
||||
and `noUncheckedIndexedAccess` settings without `any` casts. The
|
||||
`buildHeaderValue` guard checks for `null`/`undefined`/non-object
|
||||
rather than `typeof === "string"` because the input is structured —
|
||||
mismatching that guard would let through invalid shapes.
|
||||
Reference in New Issue
Block a user