import 'reflect-metadata'; import type { WireComponent } from './component.js'; import type { WireSnapshot, WireMemo, SerializedValue } from './types.js'; import type { Synthesizer } from './synthesizers/synthesizer.js'; /** * Manages serialisation (dehydration) and deserialisation (hydration) of * `WireComponent` state to and from a `WireSnapshot`. * * The snapshot is a JSON-safe object that is signed with an HMAC-SHA256 * checksum using the application's `APP_KEY`. Any tampering with the * snapshot on the client will cause the checksum to fail on the next request, * throwing a `ChecksumException`. * * Complex types (Date, Map, Set, user-defined) are serialised using * _synthesizers_ — small objects that each handle one type. Built-in * synthesizers for Date, Map, and Set are registered automatically. * Custom synthesizers can be registered via `SnapshotManager.register()`. * * @example * ```ts * const manager = new SnapshotManager(appKey) * const snapshot = manager.dehydrate(component) * // ... round-trip through the client ... * manager.hydrate(component, snapshot) * ``` */ export declare class SnapshotManager { private readonly secret; /** * Ordered list of registered synthesizers. * Checked in order during dehydration — first match wins. */ private synthesizers; constructor(secret: string); /** * Register a custom synthesizer. * * Synthesizers are checked in the order they were registered, **before** * the built-in ones. This means a custom synthesizer for `'date'` would * shadow the built-in DateSynthesizer. * * @param synthesizer The synthesizer implementation to register */ register(synthesizer: Synthesizer): void; /** * Serialise the component's current public state into a `WireSnapshot`. * * Steps: * 1. Collect all public state (excluding computed properties — like Livewire 4, * computed values are derived fresh each request and never persisted) * 2. Serialise each value through the synthesizer pipeline * 3. Build the `memo` metadata block * 4. Sign the snapshot with an HMAC-SHA256 checksum * * @param component The component instance to serialise * @param ctx Optional request context for path/method/locale info */ dehydrate(component: WireComponent, ctx?: { path?: string; method?: string; locale?: string; }): Promise; /** * Restore a component's public state from a previously dehydrated snapshot. * * Steps: * 1. Verify the HMAC checksum — throws `ChecksumException` if invalid * 2. Hydrate each serialised value back to its original type * 3. Set properties on the component instance (skipping computed keys * to avoid shadowing prototype methods with primitive values) * 4. Restore `$id`, `$name`, and `$errors` from the memo * * @param component The component instance to restore into * @param snapshot The snapshot received from the client */ hydrate(component: WireComponent, snapshot: WireSnapshot): void; /** * Produce an HMAC-SHA256 hex digest for the given `state` + `memo` payload. * The payload is deterministically serialised to JSON before signing. * * @internal */ sign(payload: { state: Record; memo: WireMemo; }): string; /** * Verify the checksum on a snapshot. * Throws `ChecksumException` if the snapshot has been tampered with. * * Uses a timing-safe comparison to prevent timing attacks. * * @internal */ verify(snapshot: WireSnapshot): void; /** * Recursively serialise a single value. * * - Primitives (string, number, boolean, null, undefined) → pass through * - Arrays → each element is recursively serialised * - Plain objects → each value is recursively serialised * - Complex types → first matching synthesizer produces a tuple `[data, meta]` * - Unrecognised types → `null` (logged in dev, silently dropped in prod) * * @internal */ dehydrateValue(value: unknown): SerializedValue; /** * Recursively hydrate a single serialised value back to its original type. * * - Primitives → pass through * - Arrays that look like a `[data, { s: 'type' }]` tuple → find synthesizer * - Plain arrays → each element is recursively hydrated * - Plain objects → each value is recursively hydrated * * @internal */ hydrateValue(value: SerializedValue): unknown; } /** * Thrown by `SnapshotManager.verify()` when the HMAC checksum on an incoming * snapshot does not match the expected value. * * This typically means the snapshot was tampered with on the client, or the * `APP_KEY` was rotated between the initial render and this request. */ export declare class ChecksumException extends Error { constructor(message: string); }