/** * Load Coordinator - Request deduplication for component on_load() calls * * Coordinates parallel component loading to prevent duplicate requests. * When multiple components with identical names and args load simultaneously, * only the first (leader) executes on_load(). Others (followers) wait for * the leader's result. * * Key Concepts: * - **INVOCATION_KEY**: Unique identifier for component name + args combination * - **Leader**: First component to reach on_load() for a given INVOCATION_KEY * - **Follower**: Subsequent components that wait for leader's result * * Lifecycle: * 1. Leader reaches on_load() → create coordination entry * 2. Followers reach on_load() → join waiting queue * 3. Leader completes → distribute data to all followers * 4. Clear coordination entry (no caching) * * The hand-off is a copy, and it is made by the cache serializer * (Jqhtml_Local_Storage.serialize()/deserialize()), never by JSON.stringify. * A follower never runs on_load() and never revalidates, so whatever it is * handed is final: the copy has to rebuild Date, Map, Set and every * register_cache_class() instance exactly as the leader's this.data holds them. * JSON.stringify would consult toJSON() and hand out a wire form that * normalize_for_cache() cannot recognise - the follower would then render * against plain objects while the leader renders against instances. * * @internal This class is not exposed in the public API */ import type { Jqhtml_Component } from './component.js'; export interface InvocationKeyResult { key: string | null; uncacheable_property?: string; /** Why the property could not be keyed - 'function', 'circular', 'too-large', ... */ uncacheable_reason?: string; } export interface InvocationKeyOptions { /** * Allow a plain-data object/array arg with no author-supplied cache id to be * keyed by DETERMINISTIC CONTENT. * * The CACHE passes true: two structurally equal args should hit the same * cache entry, and a wrong key there is corrected by stale-while-revalidate. * * DEDUPLICATION passes false (the default), deliberately. A deduplicated * follower never runs on_load() at all and adopts the leader's data with no * revalidation, so a key that is wrong there is permanently wrong data. * Redundant concurrent requests are cheaper than that risk. */ allow_content_serialization?: boolean; } export declare class Load_Coordinator { private static _registry; /** * Generate INVOCATION_KEY from component name and args * Uses deterministic JSON serialization (sorted keys) * Excludes internal properties (those starting with _) * * For functions/objects: * - Checks for ._jqhtml_cache_id property (assigned by RSpade) * - Falls back to .jqhtml_cache_id() method if property doesn't exist * - If neither exists, marks property as uncacheable * * Returns object with: * - key: Cache key string, or null if uncacheable * - uncacheable_property: Name of first property that prevented caching (for debugging) */ static generate_invocation_key(component_name: string, args: any, options?: InvocationKeyOptions): InvocationKeyResult; /** * Check if a component should execute on_load() or wait for existing request * Returns true if component should execute (is leader), false if should wait (is follower) * * @param key - The dedup key the caller captured for this load. Every coordinator * method takes it, because args may legally change during on_load() * and a recomputed key would address a different (or no) entry. */ static should_execute_on_load(component: Jqhtml_Component, key: string): boolean; /** * Register a leader component that will execute on_load() * Creates coordination entry and returns a function to call when data is ready * * @param key - The dedup key captured by the caller (see should_execute_on_load) * @returns A function that accepts the final data and completes coordination */ static register_leader(component: Jqhtml_Component, key: string): (final_text: string | null) => void; /** * Get the coordination promise for a follower component * Returns a promise that resolves when the leader completes, or rejects if it failed */ static get_coordination_promise(key: string): Promise | null; /** * Complete coordination after leader's on_load() finishes * Stores leader's data, marks entry as completed, and resolves the promise. * Followers retrieve the data themselves via get_leader_data(). * * @param key - The coordination key captured at registration * @param leader - The leader component * @param final_text - The leader's final this.data as Jqhtml_Local_Storage.serialize() * text - the text the leader already holds for change detection * @private */ private static _complete_coordination; /** * Get leader's data for a follower component * Called by follower after coordination promise resolves * Returns a freshly parsed copy and cleans up if this is the last follower * * @param key - The dedup key captured by the follower before it began waiting */ static get_leader_data(component: Jqhtml_Component, key: string): Record | null; /** * Handle a failed leader load: on_load() threw, or applying its result failed * (non-object this.data, or on_loaded() threw). * Rejects every waiting follower and clears the entry so the next component retries * * @param key - The dedup key captured at registration */ static handle_leader_error(key: string, error: Error): void; /** * Get current registry state (for debugging) */ static get_registry_state(): any; /** * Clear all coordination entries (for testing/debugging) */ static clear_all(): void; } //# sourceMappingURL=load-coordinator.d.ts.map