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,84 @@
# dmarc-error
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Defines the lightweight error class and stable code registry for `@suaveplan/dmarc`. Because this package carries no `@suaveplan/error` runtime dependency (it is a leaf package with no `@suaveplan/*` runtime deps), it provides its own self-contained error substrate that gives callers the same discriminated-error contract: a strongly-typed `code` field for `switch`/`instanceof` discrimination, plus an idiomatic `cause` chain via the built-in `ErrorOptions`.
## Features
- `DMARC_CODES` — three stable string-literal constants (`DMARC.PARSE_ERROR`, `DMARC.INVALID_REPORT`, `DMARC.UNSUPPORTED_ENCODING`)
- `DmarcCode` — union type of all valid code values
- `DmarcError` — `Error` subclass with a `readonly code: DmarcCode` field and preserved `name`
## Usage: Basic Example
```ts
import { DmarcError, DMARC_CODES } from "@suaveplan/dmarc/errors";
try {
// ... parse logic
} catch (cause) {
throw new DmarcError(DMARC_CODES.PARSE_ERROR, "Failed to parse XML", { cause });
}
```
## Usage: Advanced Example
```ts
import { DmarcError, DMARC_CODES, type DmarcCode } from "@suaveplan/dmarc/errors";
function handleDmarcError(err: unknown): never {
if (err instanceof DmarcError) {
switch (err.code) {
case DMARC_CODES.PARSE_ERROR:
console.error("XML parse failure:", err.message, err.cause);
break;
case DMARC_CODES.INVALID_REPORT:
console.error("Schema validation failed:", err.message);
break;
case DMARC_CODES.UNSUPPORTED_ENCODING:
console.error("Cannot decode input:", err.message);
break;
}
}
throw err;
}
```
## API Reference
### `DMARC_CODES`
`{ PARSE_ERROR: "DMARC.PARSE_ERROR"; INVALID_REPORT: "DMARC.INVALID_REPORT"; UNSUPPORTED_ENCODING: "DMARC.UNSUPPORTED_ENCODING" }`
Immutable code registry. Use these constants instead of raw strings so that typos produce type errors.
### `DmarcCode`
`"DMARC.PARSE_ERROR" | "DMARC.INVALID_REPORT" | "DMARC.UNSUPPORTED_ENCODING"`
Union of all valid code values for use in signatures and `switch` exhaustiveness checks.
### `DmarcError`
`class DmarcError extends Error`
**Constructor:** `new DmarcError(code: DmarcCode, message: string, options?: ErrorOptions)`
- `code` — one of the `DMARC_CODES` values
- `message` — human-readable description
- `options.cause` — original error for cause-chain logging
**Properties:**
- `code: DmarcCode` — readonly; set during construction
- `name: string` — always `"DmarcError"`
**Throws:** nothing
## Implementation Notes
The absence of `@suaveplan/error` as a runtime dependency is intentional: this package is a leaf node in the dependency graph and must remain importable in environments where the broader Suaveplan stack is not installed. The same discriminated-error pattern (stable `code` field, `cause` chain, subclassed `Error`) is preserved so that tooling and callers that understand `@suaveplan/error` conventions can handle these errors uniformly.

View File

@@ -0,0 +1,48 @@
import { describe, expect, it } from "@suaveplan/testing/runner";
import { DMARC_CODES, DmarcError } from "./dmarc-error.js";
describe("DMARC_CODES", () => {
it("has the expected code values", { timeout: 5000 }, () => {
expect(DMARC_CODES.PARSE_ERROR).toBe("DMARC.PARSE_ERROR");
expect(DMARC_CODES.INVALID_REPORT).toBe("DMARC.INVALID_REPORT");
expect(DMARC_CODES.UNSUPPORTED_ENCODING).toBe(
"DMARC.UNSUPPORTED_ENCODING"
);
});
});
describe("DmarcError", () => {
it("is an instance of Error", { timeout: 5000 }, () => {
const err = new DmarcError(DMARC_CODES.PARSE_ERROR, "test");
expect(err).toBeInstanceOf(Error);
});
it("has the correct name", { timeout: 5000 }, () => {
const err = new DmarcError(DMARC_CODES.PARSE_ERROR, "test");
expect(err.name).toBe("DmarcError");
});
it("sets the code field", { timeout: 5000 }, () => {
const err = new DmarcError(DMARC_CODES.INVALID_REPORT, "bad report");
expect(err.code).toBe(DMARC_CODES.INVALID_REPORT);
});
it("sets the message field", { timeout: 5000 }, () => {
const err = new DmarcError(DMARC_CODES.PARSE_ERROR, "my message");
expect(err.message).toBe("my message");
});
it("stores cause when provided", { timeout: 5000 }, () => {
const cause = new Error("original");
const err = new DmarcError(DMARC_CODES.UNSUPPORTED_ENCODING, "wrap", {
cause,
});
expect(err.cause).toBe(cause);
});
it("works with instanceof discrimination", { timeout: 5000 }, () => {
const err = new DmarcError(DMARC_CODES.PARSE_ERROR, "x");
expect(err instanceof DmarcError).toBe(true);
expect(err instanceof Error).toBe(true);
});
});

View File

@@ -0,0 +1,47 @@
/**
* DMARC error codes as string literal constants.
*
* All codes are prefixed with `DMARC.` and fall into three categories:
* - `DMARC.PARSE_ERROR` — XML parsing or structural failure
* - `DMARC.INVALID_REPORT` — the parsed structure does not conform to the DMARC schema
* - `DMARC.UNSUPPORTED_ENCODING` — input encoding cannot be handled (not gzip, not UTF-8)
*/
export const DMARC_CODES = {
PARSE_ERROR: "DMARC.PARSE_ERROR",
INVALID_REPORT: "DMARC.INVALID_REPORT",
UNSUPPORTED_ENCODING: "DMARC.UNSUPPORTED_ENCODING",
} as const;
export type DmarcCode = (typeof DMARC_CODES)[keyof typeof DMARC_CODES];
/**
* Lightweight error class for all `@suaveplan/dmarc` failures.
*
* Extends the built-in `Error` with a strongly-typed `code` field drawn from
* `DMARC_CODES`. Since this package carries no `@suaveplan/error` runtime
* dependency, this is a self-contained substitute that provides the same
* discriminated-error contract to callers.
*
* @example
* ```ts
* import { DmarcError, DMARC_CODES } from "@suaveplan/dmarc/errors";
*
* throw new DmarcError(DMARC_CODES.PARSE_ERROR, "Unexpected root element", {
* cause: originalError,
* });
* ```
*/
export class DmarcError extends Error {
/** Stable string code identifying the failure kind. */
public readonly code: DmarcCode;
public constructor(
code: DmarcCode,
message: string,
options?: ErrorOptions
) {
super(message, options);
this.name = "DmarcError";
this.code = code;
}
}

View File

@@ -0,0 +1 @@
export { DMARC_CODES, type DmarcCode, DmarcError } from "./dmarc-error";