/** * Live named-query subscriptions (subscribeQuery) - HTTP client poller (v1). * * A standardized client-side poller for a policy's computed/named queries. Same * callback contract as `subscribe()` (onData/onError), but instead of a socket it * polls `runQuery` on an interval. It exists to replace ad-hoc app-side polling * with one controlled, deduped, backoff-aware poller. * * v1 is HTTP-only and requires ZERO server change: it rides the existing * `runQuery` microtask coalescer (operations.ts), which batches due keys into * <=10-per-POST chunks, surfaces per-row errors, and (via utils/api) does a * bounded in-request 429 retry. The websocket transport and true server-push are * deferred; see LIVE-QUERIES-SDK-PLAN.md section 9. The public contract here is * pinned so either upgrade stays transparent. * * Design notes that are load-bearing (do not "simplify" away): * - The coalescer does NOT dedupe; the manager's refcount dedupe below is the * ONLY dedupe, so it is load-bearing for billed-read correctness. * - There is no durable transport backoff: `utils/api` retries twice then * rejects. Steady-state backoff on a rejected poll is owned HERE. * - A transport rejection (429/network/chunk) must NOT reach onError - it would * blast the whole up-to-10-key chunk every interval and rebuild the exact 429 * noise this feature removes. Only a genuine per-row query error / policy * decline reaches onError. */ /** Default poll cadence. Sits on the hot named-query cadence oapps already runs. */ export declare const DEFAULT_QUERY_POLL_INTERVAL_MS = 5000; /** Hard lower clamp so an app cannot rebuild the 429 storm. */ export declare const MIN_QUERY_POLL_INTERVAL_MS = 1000; export interface QuerySubscriptionOptions { /** Called with the computed value on the first fetch and on every CHANGE. */ onData?: (data: any) => void; /** * Called advisory-only on a genuine query error / policy decline; the last * good value stays on screen (never cleared). NOT called for transient * transport failures (429/network) - those back off silently. The error * carries `.phase: 'initial' | 'refresh'` and `.willRetry: boolean` (plus the * usual `.isQueryError/.queryName/.path` or `.decline/.isBoundedDecline`). */ onError?: (error: any) => void; /** Poll cadence in ms. Defaults to 5000, clamped to a 1000 floor. */ intervalMs?: number; } type ResolvedIdentity = { bucket: string; token: string | null; }; /** * Deterministic key-sorted serialization of query args, canonicalizing the EXACT * JSON wire representation the request serializer sends. Args are first projected * through `JSON.parse(JSON.stringify(...))` so `toJSON` runs (a `Date` becomes its * ISO string, not `{}`) and functions/`undefined` are dropped exactly as the wire * does, then key-sorted with null-prototype objects so an own `__proto__` key * round-trips as a property. This makes the dedupe key match what the server * actually receives, so two subscriptions can share a poller only when their wire * inputs are identical. Cyclic structures and other values the wire cannot * serialize (e.g. `BigInt`) are rejected by `JSON.stringify` here, exactly as they * would be on the wire. */ export declare function canonicalizeArgs(args: any): string; /** * Deterministic key-sorted serialization of a query RESULT for change detection. * Robust to shuffled object key order and the JSON-wire shapes the endpoint * yields (string u64, ISO-date string). BigInt/Date OBJECTS never cross the HTTP * boundary, so they are intentionally not handled here. */ export declare function canonicalizeResult(result: any): string; /** * Subscribe to the live value of a named (computed) query. * * @param path - The document path the query is declared on (e.g. 'market/mytoken'). * @param queryName - The named query to run (e.g. 'tokensForOneSol'). * @param args - Query arguments (canonicalized; drives the dedupe key). * @param options - onData/onError callbacks and optional intervalMs; a bare * function is coerced to `{ onData }` (mirrors subscribe()). * @returns An async unsubscribe function. * * @example * ```typescript * const unsubscribe = await subscribeQuery('market/mytoken', 'tokensForOneSol', {}, { * onData: (price) => setPrice(price), * onError: (err) => { if (err.phase === 'initial') showSpinnerError(); }, * }); * await unsubscribe(); * ``` */ export declare function subscribeQuery(path: string, queryName: string, args: any, options?: QuerySubscriptionOptions | ((data: any) => void)): Promise<() => Promise>; /** * Wired to the SDK's auth-change chokepoint (operations.clearReadCacheForAuthChange, * driven by reconnectWithNewAuth). That chokepoint fires on ANY reconnect - including * a transient browser `online` nudge - not only on a real identity change, so this * MUST be idempotent when the principal is unchanged: it re-resolves identity per * key and re-keys ONLY the entries whose principal actually changed, preserving the * timer and backoff of every unchanged entry (otherwise a flaky connection would * rebuild the exact 429 re-poll storm this feature removes). */ export declare function notifyQueryAuthChanged(): void; /** Tear down every query subscription: cancel timers, clear the registry. */ export declare function closeAllQuerySubscriptions(): void; /** @internal Reset all manager state between test scenarios. */ export declare function __resetForTest(): void; /** @internal Force an out-of-band tick on a key (single-flight assertions). Returns whether a matching entry was found. */ export declare function __pollNowForTest(appId: string, path: string, queryName: string, args: any, identity: ResolvedIdentity): boolean; /** @internal Drive visibility without a DOM. */ export declare function __setVisibilityForTest(nextHidden: boolean): void; /** @internal Snapshot registry state for assertions. */ export declare function __inspectForTest(): { keys: string[]; hidden: boolean; liveSubscribers: number; }; export {};