Initial Commit
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
export {
|
||||
PSEUDO_RANDOM_CODES,
|
||||
type PseudoRandomCode,
|
||||
PseudoRandomError,
|
||||
} from "./pseudo-random-error";
|
||||
@@ -0,0 +1,64 @@
|
||||
# pseudo-random-error
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `pseudo-random-error` module defines the stable, code-based error surface for the `@suaveplan/pseudo-random` package. Every failure raised by this package — bad seeds, corrupt checkpoints, invalid arguments to helpers — is reported through a single `PseudoRandomError` class whose `code` is drawn from the frozen `PSEUDO_RANDOM_CODES` registry.
|
||||
|
||||
Centralising error codes gives callers a narrow contract: they can pattern-match on `PSEUDO_RANDOM_CODES["SEED.INVALID"]` instead of string-matching messages, and translators have a finite list of keys to localise.
|
||||
|
||||
## Features
|
||||
|
||||
- Frozen, namespaced error-code registry via `defineCodes`
|
||||
- `PseudoRandomError` extends `SuaveplanError` and inherits cause-chain traversal, redaction, OTel mapping and the Zod-validated wire format
|
||||
- Codes cover every validation branch in the package: seed normalisation, state restoration, helper-argument checks
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { PseudoRandomError, PSEUDO_RANDOM_CODES } from "@suaveplan/pseudo-random/errors";
|
||||
|
||||
throw new PseudoRandomError(
|
||||
PSEUDO_RANDOM_CODES["SEED.INVALID"],
|
||||
"pseudo_random.seed.invalid",
|
||||
{ context: { value: "???" } },
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { PseudoRandomError, PSEUDO_RANDOM_CODES } from "@suaveplan/pseudo-random/errors";
|
||||
|
||||
function assertFiniteSeed(seed: number): void {
|
||||
if (!Number.isFinite(seed)) {
|
||||
throw new PseudoRandomError(
|
||||
PSEUDO_RANDOM_CODES["SEED.NOT_FINITE"],
|
||||
"pseudo_random.seed.not_finite",
|
||||
{ context: { seed } },
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `PSEUDO_RANDOM_CODES` — the frozen registry of string error codes.
|
||||
- `PseudoRandomError(code, messageKey, options?)` — structured error carrying the code, an i18n key and the standard `SuaveplanErrorOptions` (context/cause/sensitive).
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
All codes are stable strings (`PSEUDO_RANDOM.*`), suitable for catalog lookup and wire-serialisation. No runtime dependencies beyond `@suaveplan/error`; no OTel emission here — error observability lives in the caller.
|
||||
|
||||
### Subclasses & Codes
|
||||
|
||||
`PseudoRandomError` is the base class for every error thrown by the seeded-RNG implementations. Subclasses cover invalid seed (non-finite, out-of-range), invalid state restore (state vector of wrong length), and exhaustion (fixed-period generators that have cycled past `Number.MAX_SAFE_INTEGER` draws). All codes live under the `PSEUDO_RANDOM` namespace.
|
||||
|
||||
## Further Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { PseudoRandomError } from "@suaveplan/pseudo-random/errors/pseudo-random-error";
|
||||
throw new PseudoRandomError("bad seed", { code: "PSEUDO_RANDOM.INVALID_SEED" });
|
||||
```
|
||||
@@ -0,0 +1,35 @@
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import {
|
||||
PSEUDO_RANDOM_CODES,
|
||||
PseudoRandomError,
|
||||
} from "./pseudo-random-error.js";
|
||||
|
||||
describe("PseudoRandomError", () => {
|
||||
it("carries a stable code and message key", { timeout: 5000 }, () => {
|
||||
const err = new PseudoRandomError(
|
||||
PSEUDO_RANDOM_CODES["SEED.INVALID"],
|
||||
"pseudo_random.seed.invalid"
|
||||
);
|
||||
expect(err).toBeInstanceOf(PseudoRandomError);
|
||||
expect(err.code).toBe("PSEUDO_RANDOM.SEED.INVALID");
|
||||
expect(typeof err.timestamp).toBe("number");
|
||||
});
|
||||
|
||||
it("accepts context and cause", { timeout: 5000 }, () => {
|
||||
const cause = new Error("boom");
|
||||
const err = new PseudoRandomError(
|
||||
PSEUDO_RANDOM_CODES["STATE.INVALID"],
|
||||
"pseudo_random.state.invalid",
|
||||
{ context: { where: "restore" }, cause }
|
||||
);
|
||||
expect(err.context).toEqual({ where: "restore" });
|
||||
expect(err.cause).toBe(cause);
|
||||
});
|
||||
|
||||
it("registry has all namespaces", { timeout: 5000 }, () => {
|
||||
expect(PSEUDO_RANDOM_CODES["SEED.INVALID"]).toMatch(/^PSEUDO_RANDOM\./);
|
||||
expect(PSEUDO_RANDOM_CODES["ARG.EMPTY_ARRAY"]).toBe(
|
||||
"PSEUDO_RANDOM.ARG.EMPTY_ARRAY"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import {
|
||||
defineCodes,
|
||||
SuaveplanError,
|
||||
type SuaveplanErrorOptions,
|
||||
} from "@suaveplan/error";
|
||||
|
||||
/**
|
||||
* Error code registry for `@suaveplan/pseudo-random`.
|
||||
*/
|
||||
export const PSEUDO_RANDOM_CODES = defineCodes("PSEUDO_RANDOM", [
|
||||
"SEED.INVALID",
|
||||
"SEED.NOT_FINITE",
|
||||
"SEED.NOT_SAFE_INT",
|
||||
"STATE.INVALID",
|
||||
"STATE.ALGORITHM_MISMATCH",
|
||||
"ARG.INVALID",
|
||||
"ARG.EMPTY_ARRAY",
|
||||
"ARG.NEGATIVE_COUNT",
|
||||
"ARG.WEIGHTS_INVALID",
|
||||
] as const);
|
||||
|
||||
export type PseudoRandomCode =
|
||||
(typeof PSEUDO_RANDOM_CODES)[keyof typeof PSEUDO_RANDOM_CODES];
|
||||
|
||||
/** Typed error for `@suaveplan/pseudo-random`. */
|
||||
export class PseudoRandomError extends SuaveplanError<PseudoRandomCode> {
|
||||
// biome-ignore lint/complexity/noUselessConstructor: widens visibility
|
||||
public constructor(
|
||||
code: PseudoRandomCode,
|
||||
messageKey: string,
|
||||
options?: SuaveplanErrorOptions
|
||||
) {
|
||||
super(code, messageKey, options);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user