first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
# `assess-reactive` — streaming assessment with debounce + cancel
## Purpose
Debounce + cancel-on-newer-input wrapper around `assess` for UI strength
meters that update as the user types. Each new input cancels the pending
assessment for the previous input; only the latest stable value reaches
the consumer. The wrapper honours an optional `AbortSignal` so callers
can tear down a meter without orphaning pending work.
## Features
- Configurable `debounceMs` (default 150 ms, range `[0, 5000]`)
- Cancel-on-newer-input — superseded inputs do not yield results
- Clean `AbortSignal` completion (no thrown error on abort)
- 200-character DoS guard surfaced as `INPUT_TOO_LONG`
- Backed by an `AsyncIterable<StrengthResult>` so consumers integrate via
`for await`
## Usage: Basic Example
```ts
import { assessReactive } from "@suaveplan/password-strength";
async function* keystrokes() {
yield "p";
yield "pa";
yield "pas";
yield "pass";
}
for await (const r of assessReactive(keystrokes())) {
console.log(r.password, r.score);
}
```
## Usage: Advanced Example
```ts
import { assessReactive } from "@suaveplan/password-strength";
const controller = new AbortController();
const stream = assessReactive(keystrokes(), {
debounceMs: 100,
signal: controller.signal,
assessOptions: { userInputs: ["alice@example.com"] },
});
setTimeout(() => controller.abort(), 50);
for await (const r of stream) {
console.log(r.score);
}
```
## API Reference
- `assessReactive(input$: AsyncIterable<string>, opts?: AssessReactiveOptions): AsyncIterable<StrengthResult>`
- Throws `PasswordStrengthError(PWSTRENGTH.INVALID_OPTIONS)` on schema
failure; throws `PasswordStrengthError(PWSTRENGTH.INPUT_TOO_LONG)` when
an input exceeds 200 characters.
- `AssessReactiveOptions`: `{ debounceMs?, signal?, assessOptions? }`.
## Implementation Notes
The wrapper schedules each input via `setTimeout(debounceMs)`. A newer
input cancels the pending timer and reschedules. Consumers awaiting the
next iteration are tracked in an internal resolver queue; an emitted
result settles the next resolver or buffers if none is waiting. Abort
clears the pending timer and resolves every waiting consumer with
`{ done: true }`; the iterable then completes cleanly without throwing.
The `ABORTED` error code is registered with the OTel counter on abort so
operators can monitor cancellation rates without inspecting the iterator
itself.