@voltro/client 0.38.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -296,8 +296,18 @@ export declare interface BuildApiRuntimeOptions {
296
296
  readonly name: string;
297
297
  /** WebSocket URL of the api (`ws(s)://host:port/ws`). */
298
298
  readonly wsUrl: string;
299
- /** The api's rpc group (its typed procedure surface). */
300
- readonly group: RpcGroup.RpcGroup<Rpc.Any>;
299
+ /**
300
+ * The api's rpc group, as the ERASED `RpcGroup.Any`.
301
+ *
302
+ * `RpcGroup` is declared `in out` in @effect/rpc — invariant on purpose — so a
303
+ * CONCRETE group (the `appGroup` codegen emits) is not assignable to
304
+ * `RpcGroup<Rpc.Any>`, and a boundary typed that way rejects the only value
305
+ * anyone ever passes it. This mirrors what `ApiHandle.client` already does:
306
+ * erase at the handle boundary, restore the types at the call site via
307
+ * `createHooks<T>()` / `useAppClient<T>()`. The concrete rpc types are
308
+ * irrelevant to building a transport — they matter to the caller, not here.
309
+ */
310
+ readonly group: RpcGroup.Any;
301
311
  /** Per-connection auth headers (see {@link ResolvableHeaders}). */
302
312
  readonly headers?: ResolvableHeaders | undefined;
303
313
  /** How to construct a WebSocket. Web wraps `globalThis.WebSocket` with
@@ -306,6 +316,8 @@ export declare interface BuildApiRuntimeOptions {
306
316
  readonly webSocketConstructor: (url: string, protocols?: string | ReadonlyArray<string>) => globalThis.WebSocket;
307
317
  }
308
318
 
319
+ export declare type BuildClient = (api: MountedApi, generation: number, onSocketOpen: () => void, onSocketIssue: (kind: SocketIssueKind) => void) => Promise<ResolvedClient>;
320
+
309
321
  /** The transport-level pieces of one api's client stack. Combined with the
310
322
  * api's descriptor map + inspect base URL, this is an `ApiHandle`. */
311
323
  export declare interface BuiltApiRuntime {
@@ -349,6 +361,11 @@ declare interface CacheEntry {
349
361
  * server-side subscription is one per cache-entry key, not per
350
362
  * subscriber. */
351
363
  fetch: (() => Stream.Stream<SubscriptionEvent<unknown>, unknown, never>) | null;
364
+ /** The runtime the saved `fetch` was forked against. Stored so a SINGLE entry
365
+ * can be re-issued without the whole-cache `refreshAll(runtime)` — the
366
+ * confirmed-patch resync needs exactly one, and threading a runtime down
367
+ * from a `setTimeout` is not available to it. */
368
+ runtime: AnyRuntime | null;
352
369
  /** W3C trace id of the live stream, captured when the fiber starts.
353
370
  * Shared with the server (the subscription span propagates it) and
354
371
  * attached to error-bus events so a failure points at the right
@@ -492,6 +509,20 @@ export declare const clearStoreHistory: () => void;
492
509
 
493
510
  export declare const CLIENT_NAME: "framework-client";
494
511
 
512
+ /**
513
+ * Per-rpc-tag metadata the client uses to route cache updates: what kind of
514
+ * procedure a tag is, which query it reads from, and which tables a mutation
515
+ * targets (driving auto-optimistic updates). Produced by codegen.
516
+ *
517
+ * It is the CANONICAL `ClientDescriptor` from `@voltro/protocol`, not a
518
+ * structural copy of it. The copy that used to live here narrowed `source` to a
519
+ * single string while the real descriptor allows several — so a generated
520
+ * `appDescriptors` did not fit the type the client declared for it. Nothing
521
+ * caught that: the only place the two meet is a GENERATED entry, and no harness
522
+ * typechecks a generated entry.
523
+ */
524
+ export declare type ClientDescriptorMap = Readonly<Record<string, ClientDescriptor>>;
525
+
495
526
  export declare interface ClientErrorEvent {
496
527
  /** The thrown value (Error | anything). */
497
528
  readonly error: unknown;
@@ -1047,6 +1078,27 @@ export declare const markFailed: (queue: Outbox, id: string, error: unknown) =>
1047
1078
 
1048
1079
  export declare const markSent: (queue: Outbox, id: string) => Outbox;
1049
1080
 
1081
+ /**
1082
+ * One api the client is mounted against: its name, its typed rpc surface, its
1083
+ * descriptor map and where to connect.
1084
+ *
1085
+ * `headers` are sent in the per-request MESSAGE frame, NOT the WebSocket
1086
+ * upgrade — a browser cannot set upgrade headers — so the server's
1087
+ * AuthMiddleware sees them on every call, which is what lets a cross-origin api
1088
+ * authenticate WS subscriptions. A thunk is resolved fresh on every (re)connect,
1089
+ * so a rotating token is pulled anew per connection instead of frozen at first
1090
+ * mount.
1091
+ */
1092
+ export declare interface MountedApi {
1093
+ readonly name: string;
1094
+ /** Erased — see `BuildApiRuntimeOptions.group` for why an invariant
1095
+ * `RpcGroup<Rpc.Any>` cannot hold a generated `appGroup`. */
1096
+ readonly group: RpcGroup.Any;
1097
+ readonly descriptors: ClientDescriptorMap;
1098
+ readonly wsUrl: string;
1099
+ readonly headers?: ResolvableHeaders | undefined;
1100
+ }
1101
+
1050
1102
  export declare interface MutateOptions<Input, Output> {
1051
1103
  /** Ran after the server confirms the write. */
1052
1104
  readonly onSuccess?: (output: Output, input: Input) => void;
@@ -1242,6 +1294,31 @@ export declare interface PersistOptions<S> {
1242
1294
  * `initialSnapshot` are its own concern. */
1243
1295
  export declare type PreloadedSubscriptionOptions = Pick<SubscriptionOptions<never>, 'skip'>;
1244
1296
 
1297
+ /**
1298
+ * What this hook returns: the subscription's state, plus whether the SERVER
1299
+ * tried to preload it and failed.
1300
+ *
1301
+ * `preloadFailed` is the difference between "this page has no data yet" and
1302
+ * "the server could not get this page's data" — two states that were one
1303
+ * observation before it existed, because both arrive as the absence of a seed.
1304
+ * A consumer whose session had expired rendered skeleton titles over empty
1305
+ * tables and found the cause only in a server WARN line.
1306
+ *
1307
+ * It says nothing about WHY, deliberately (`PreloadSeed.failed`), and nothing
1308
+ * about the LIVE subscription — which usually recovers on its own, since the
1309
+ * browser reconnects with a credential the SSR request did not have. So the
1310
+ * honest reading is "the first paint has no server data and that was not for
1311
+ * lack of asking", which is exactly enough to choose a spinner over an
1312
+ * empty-state.
1313
+ *
1314
+ * Widened on THIS hook rather than on `SubscriptionState`, so no existing
1315
+ * `useSubscription` call site is un-narrowed by it — the same scoping rule the
1316
+ * `skip`/`idle` overload follows.
1317
+ */
1318
+ export declare type PreloadedSubscriptionState<T> = (SubscriptionState<T> | SubscriptionIdle) & {
1319
+ readonly preloadFailed?: true;
1320
+ };
1321
+
1245
1322
  /** One preloaded subscription snapshot, as it travels in the hydration payload. */
1246
1323
  export declare interface PreloadSeed {
1247
1324
  /** The api mount name the subscription reads from (first arg of `useSubscription`). */
@@ -1249,8 +1326,25 @@ export declare interface PreloadSeed {
1249
1326
  /** `stableKey([rpcTag, input])` — identical to the SubscriptionCache's own key,
1250
1327
  * so the seed and the live subscription address the same entry. */
1251
1328
  readonly key: string;
1252
- /** The server-fetched snapshot value. */
1329
+ /** The server-fetched snapshot value. `undefined` when `failed`. */
1253
1330
  readonly value: unknown;
1331
+ /**
1332
+ * The server ATTEMPTED this preload and it failed.
1333
+ *
1334
+ * Reported by a consumer whose SSR seeds all failed at once (an expired
1335
+ * session token — the api answered every preload with a scope error): the
1336
+ * page rendered a skeleton title and an empty table, and the ONLY record of
1337
+ * it was a `preload seed failed` WARN in the server log. The client could not
1338
+ * tell that state from "this page declares no preload", because both arrive
1339
+ * as the absence of a seed. So an app cannot distinguish "still loading" from
1340
+ * "actually empty" without inventing its own convention — which the reporting
1341
+ * consumer then did, page by page.
1342
+ *
1343
+ * NOTHING about the cause travels. A boolean is the whole contract: the
1344
+ * server's failure text is for the server's log, and a reason string here
1345
+ * would be an error message from a refused call rendered into a browser.
1346
+ */
1347
+ readonly failed?: true;
1254
1348
  }
1255
1349
 
1256
1350
  /** Collects preload seeds for ONE request. The server creates one per render. */
@@ -1389,6 +1483,17 @@ export declare interface QueryFiltersState<Row> {
1389
1483
 
1390
1484
  declare type QueryTag<P extends ProcedureTypeMap> = TagsOfKind<P, 'query'>;
1391
1485
 
1486
+ /**
1487
+ * Did the server attempt this preload, and did it work?
1488
+ *
1489
+ * `'absent'` means the page declared no preload for it (or the server never
1490
+ * rendered this route — a client-side SPA navigation). `'failed'` means the
1491
+ * server tried and the query threw. Those two were the same observation before
1492
+ * this existed, which is why a page could not tell "still loading" from
1493
+ * "genuinely empty".
1494
+ */
1495
+ export declare const readPreloadedSeedOutcome: (api: string, rpcTag: string, input: Readonly<Record<string, unknown>>) => "seeded" | "failed" | "absent";
1496
+
1392
1497
  /**
1393
1498
  * The preloaded snapshot for `(api, rpcTag, input)`, or `undefined` when none was
1394
1499
  * seeded. On the SERVER it reads the current request's bag directly, so the SSR
@@ -1433,6 +1538,9 @@ export declare const resetPreloadSeeds: () => void;
1433
1538
  /** Test helper: forget every defined store. NEVER call this in app code. */
1434
1539
  export declare const resetStoreRegistryForTests: () => void;
1435
1540
 
1541
+ /** Test seam: forget both the installed provider and the used flag. */
1542
+ export declare const resetStoreStorageForTest: () => void;
1543
+
1436
1544
  /** Auth headers to attach to every rpc MESSAGE frame, resolved on EVERY
1437
1545
  * (re)connect so a rotating token (a `() => Promise<…>` thunk) is fetched anew
1438
1546
  * each connection rather than frozen at first build. */
@@ -1440,6 +1548,15 @@ export declare type ResolvableHeaders = Readonly<Record<string, string>> | (() =
1440
1548
 
1441
1549
  export declare const resolveByTag: (client: unknown, tag: string) => unknown;
1442
1550
 
1551
+ export declare interface ResolvedClient {
1552
+ readonly runtime: AnyRuntime;
1553
+ readonly cache: SubscriptionCache;
1554
+ readonly client: RpcClient.RpcClient<Rpc.Any, RpcClientError.RpcClientError>;
1555
+ }
1556
+
1557
+ /** Resolve the storage for an area. Internal to the store layer. */
1558
+ export declare const resolveStoreStorage: (area: StoreStorageArea) => StoreStorage | null;
1559
+
1443
1560
  /** Resolve one map entry against the props. Pure. */
1444
1561
  export declare const resolveTrackingEvent: <P>(entry: TrackingEntry<P> | undefined, props: P) => TrackingEvent | null;
1445
1562
 
@@ -1613,6 +1730,16 @@ export declare const schemaToFields: (schema: Schema.Schema.Any) => ReadonlyArra
1613
1730
  */
1614
1731
  export declare const seedPreloadedSubscription: (api: string, rpcTag: string, input: Readonly<Record<string, unknown>>, value: unknown) => void;
1615
1732
 
1733
+ /**
1734
+ * Record that this preload was ATTEMPTED and failed, so the client can tell an
1735
+ * empty page from a broken one.
1736
+ *
1737
+ * Same request-scoping and the same key as the success path — a failure the
1738
+ * client cannot address to a subscription is no better than the WARN line it
1739
+ * replaces. It carries no reason: see `PreloadSeed.failed`.
1740
+ */
1741
+ export declare const seedPreloadedSubscriptionFailure: (api: string, rpcTag: string, input: Readonly<Record<string, unknown>>) => void;
1742
+
1616
1743
  /**
1617
1744
  * Seed a store for THIS request's hydration. Call it anywhere on the server
1618
1745
  * during a render — a loader, a layout loader — and the value reaches the
@@ -1694,6 +1821,21 @@ export declare const setPreloadSeedResolver: (resolver: (() => PreloadSeedBag |
1694
1821
  */
1695
1822
  export declare const setStoreSeedResolver: (resolver: (() => StoreSeedBag | null) | null) => void;
1696
1823
 
1824
+ /**
1825
+ * Install the process-wide backing store for persisted stores.
1826
+ *
1827
+ * Call it BEFORE the first read of a persisted store — on React Native, after
1828
+ * awaiting the adapter's `hydrate()` and before rendering the app. Pass `null`
1829
+ * to restore the browser default.
1830
+ *
1831
+ * Installing after a persisted store has already read logs a warning rather
1832
+ * than throwing: the app is running and the value is merely from the wrong
1833
+ * backend, so failing the boot would be the worse outcome. It is a warning that
1834
+ * means something, though — the store that read first is now inconsistent with
1835
+ * every store defined after it.
1836
+ */
1837
+ export declare const setStoreStorage: (provider: StoreStorageProvider | null) => void;
1838
+
1697
1839
  /**
1698
1840
  * Transition a pending mutation to 'success' or 'error'. Updates the
1699
1841
  * existing entry in-place (preserves order in the buffer) so the
@@ -1726,6 +1868,8 @@ export declare const shallowArrayEqual: (a: ReadonlyArray<unknown>, b: ReadonlyA
1726
1868
 
1727
1869
  declare type SignalPayload<Messages extends WorkflowClientMessages, Name extends string> = NonNullable<Messages['signals']> extends Readonly<Record<Name, infer Payload>> ? Payload : unknown;
1728
1870
 
1871
+ export declare type SocketIssueKind = 'close' | 'error' | 'connect-timeout';
1872
+
1729
1873
  export declare interface SortState {
1730
1874
  readonly column: string;
1731
1875
  readonly direction: 'asc' | 'desc';
@@ -1745,6 +1889,14 @@ export declare const ssrStubHandle: ApiHandle;
1745
1889
  */
1746
1890
  export declare const stableKey: (key: ReadonlyArray<unknown>) => string;
1747
1891
 
1892
+ /**
1893
+ * Spawn the per-api connect + reconnect supervisor.
1894
+ *
1895
+ * Returns a handle whose `dispose()` cancels everything pending and
1896
+ * disposes every live ResolvedClient. Calling dispose() twice is safe.
1897
+ */
1898
+ export declare const startApiSupervisor: (options: SupervisorOptions) => SupervisorHandle;
1899
+
1748
1900
  /**
1749
1901
  * Publish a NEW (pending) mutation event. Caller is responsible for
1750
1902
  * calling `settleMutation(id, ...)` later. Returns the id used to
@@ -1934,6 +2086,22 @@ export declare interface StoreSeedBag {
1934
2086
  readonly seeds: StoreSeed[];
1935
2087
  }
1936
2088
 
2089
+ /** The synchronous subset of the DOM `Storage` interface a persisted store
2090
+ * needs. `removeItem` is optional — nothing in the store layer clears keys. */
2091
+ export declare interface StoreStorage {
2092
+ readonly getItem: (key: string) => string | null;
2093
+ readonly setItem: (key: string, value: string) => void;
2094
+ readonly removeItem?: (key: string) => void;
2095
+ }
2096
+
2097
+ /** Which area a store asked for. Platforms without a session/local split map
2098
+ * both onto one backing store; that is expected, not a downgrade. */
2099
+ export declare type StoreStorageArea = 'local' | 'session';
2100
+
2101
+ /** A backing store provider: given the requested area, return the storage to
2102
+ * use, or `null` for "there is none here" (the store then does not persist). */
2103
+ export declare type StoreStorageProvider = (area: StoreStorageArea) => StoreStorage | null;
2104
+
1937
2105
  export declare interface StoreUseOptions<T> {
1938
2106
  /** Which instance to read. Omitted = the global one. */
1939
2107
  readonly key?: string;
@@ -2037,6 +2205,31 @@ export declare class SubscriptionCache {
2037
2205
  * resolve briefly exposes a stale base before the server delta lands.
2038
2206
  */
2039
2207
  confirmByMutation(mutationId: string): void;
2208
+ /**
2209
+ * The confirmed-patch window expired: a committed write never got its
2210
+ * superseding server event. Re-issue the affected subscriptions instead of
2211
+ * discarding the write's preview.
2212
+ *
2213
+ * Three things are load-bearing, and each was a way to reintroduce the bug:
2214
+ *
2215
+ * - **The patch is KEPT across the resync.** `refreshAll` already
2216
+ * establishes that shape ("the new base snapshot will land on top of
2217
+ * them"). Clearing it here would be the revert again, wearing a longer
2218
+ * word.
2219
+ * - **A stub entry — no `fetch`, no `runtime` — is left ALONE.** There is
2220
+ * nothing to re-issue, and the only other option is to show a base the
2221
+ * client knows is stale. Keeping the patch is the honest state.
2222
+ * - **It is LOUD.** The reporter found the jump only by reading minified
2223
+ * source, because in the UI it is indistinguishable from "the server did
2224
+ * not save it" — and that is the false trail they followed first. This
2225
+ * goes to the error bus, so it reaches `voltro logs` rather than only a
2226
+ * console nobody has open.
2227
+ *
2228
+ * No second timer is armed: this runs once per mutation, from the one
2229
+ * `confirmByMutation` scheduled it, so a server that never echoes cannot put
2230
+ * the client into a resync loop.
2231
+ */
2232
+ private resyncUnechoedMutation;
2040
2233
  /**
2041
2234
  * Auto-derive optimistic patches from a mutation's declared target(s).
2042
2235
  * Iterates every cache entry whose `source` table matches a target's
@@ -2098,6 +2291,18 @@ export declare class SubscriptionCache {
2098
2291
  * promote naturally on their next subscriber.
2099
2292
  */
2100
2293
  refreshAll(runtime: AnyRuntime): void;
2294
+ /**
2295
+ * Re-issue ONE entry's subscription: interrupt the fiber, reset the base,
2296
+ * re-fork through the saved `fetch`.
2297
+ *
2298
+ * Extracted so `refreshAll` and the confirmed-patch resync cannot disagree
2299
+ * about it — and the thing they must agree on is that **optimistic patches
2300
+ * survive**. For a re-auth they belong to in-flight mutations; for the resync
2301
+ * they describe a write the server has already committed. Dropping them here
2302
+ * would be a revert with a longer name, which is the defect the resync exists
2303
+ * to remove.
2304
+ */
2305
+ private reissue;
2101
2306
  /**
2102
2307
  * Seed this (fresh) cache with the last-known-good rows held by the cache it
2103
2308
  * REPLACES, so a transport rebuild degrades to STALE DATA rather than to
@@ -2315,6 +2520,98 @@ export declare interface SubscriptionStateWithFallback<T> extends SubscriptionMe
2315
2520
  readonly isEmpty: boolean;
2316
2521
  }
2317
2522
 
2523
+ /**
2524
+ * May this server event retire the CONFIRMED optimistic patches on an entry?
2525
+ *
2526
+ * **A rollback happens if and only if the write FAILED.** Nothing else — no
2527
+ * timer, no elapsed window, no "probably fine by now" — may take an optimistic
2528
+ * preview away from a write the server acknowledged. This function is the other
2529
+ * half of that rule: it decides when a patch is *superseded* rather than rolled
2530
+ * back, and superseding is only honest when the authoritative state has actually
2531
+ * arrived and actually says something.
2532
+ *
2533
+ * Three answers, each of which was a way to lose a committed write:
2534
+ *
2535
+ * - **delta → YES.** A delta IS the echo of committed writes. This is the
2536
+ * seamless hand-off: base gains the real row and the placeholder goes in the
2537
+ * same update, so there is no flash and no optimistic+real duplicate.
2538
+ * - **error → NO.** An error does not advance `base`; it sets `baseError` and
2539
+ * leaves the rows where they were. Dropping here would discard the preview
2540
+ * in favour of a base the client knows does not reflect the write.
2541
+ * - **snapshot → only if it MOVED the base.** A resync after a missing echo
2542
+ * re-asks the server, and if the answer comes back byte-identical then the
2543
+ * write is still not reflected in it. Retiring the patch on that would be
2544
+ * the reported bug reached by a longer route: the user watches their saved
2545
+ * change disappear, and the client did it while holding evidence that the
2546
+ * server's answer had not changed.
2547
+ *
2548
+ * The comparison only runs when confirmed patches exist, which is rare and
2549
+ * short-lived, so the stringify is not on any hot path.
2550
+ */
2551
+ export declare const supersedesConfirmedPatches: (event: SubscriptionEvent<unknown>, baseBefore: unknown, baseAfter: unknown) => boolean;
2552
+
2553
+ export declare interface SupervisorHandle {
2554
+ readonly dispose: () => void;
2555
+ /** Force a fresh ws connect for every api (carrying the browser's current
2556
+ * cookies) so a cookie-based login re-resolves the authenticated Subject
2557
+ * in place, without a page reload. No-op for UI-only (no-api) apps. */
2558
+ readonly reconnect: () => void;
2559
+ }
2560
+
2561
+ export declare interface SupervisorOptions {
2562
+ readonly apis: ReadonlyArray<MountedApi>;
2563
+ readonly buildClient: BuildClient;
2564
+ /**
2565
+ * Called whenever the resolved-clients map changes (initial resolve,
2566
+ * reconnect swap, api removed). The React layer mirrors this into
2567
+ * setState so the component tree sees the latest clients.
2568
+ */
2569
+ readonly onChange: (clients: ReadonlyMap<string, ResolvedClient>, initialized: boolean) => void;
2570
+ /**
2571
+ * Override the retry-delay calculation. Default: 500ms × 2^(attempt-1),
2572
+ * capped at 5s after the 5th attempt. Tests inject a deterministic
2573
+ * function so assertions don't depend on the cap shape.
2574
+ */
2575
+ readonly retryDelayMs?: (attempt: number) => number;
2576
+ /**
2577
+ * Override the stable-connection window (default 5s). When the
2578
+ * elapsed time since `onSocketOpen` exceeds this AND `failureCount`
2579
+ * hasn't moved, the connection is treated as stable and the count
2580
+ * resets to zero so the next failure starts fresh at attempt=1.
2581
+ */
2582
+ readonly stableWindowMs?: number;
2583
+ /**
2584
+ * Indirection for the JS scheduler. Production uses globalThis's
2585
+ * `setTimeout`/`clearTimeout`/`queueMicrotask`; tests inject fake
2586
+ * versions to step time deterministically.
2587
+ */
2588
+ readonly scheduler?: {
2589
+ readonly setTimeout: (cb: () => void, ms: number) => unknown;
2590
+ readonly clearTimeout: (handle: unknown) => void;
2591
+ readonly queueMicrotask: (cb: () => void) => void;
2592
+ };
2593
+ /**
2594
+ * Called when an api enters the reconnecting state, and again — via the
2595
+ * returned dispose — when it reconnects or the supervisor is torn down.
2596
+ * Exactly one entry per api per disconnect cycle: repeated retries within one
2597
+ * cycle do NOT call this again, so a status surface cannot stack duplicates.
2598
+ *
2599
+ * The web passes its devtools status bus. RN omits it.
2600
+ */
2601
+ readonly onReconnecting?: (apiName: string) => () => void;
2602
+ /**
2603
+ * Recovery for a socket that never re-opens (see the note above `ApiSlot`).
2604
+ * `arm` is called once, for an api that HAD been healthy, after
2605
+ * `afterFailures` consecutive failed reconnects; its returned stop function
2606
+ * runs on the next successful open or on dispose. What arming DOES is the
2607
+ * caller's: the web polls the page origin and hard-reloads when it answers.
2608
+ */
2609
+ readonly wedgeBackstop?: {
2610
+ readonly afterFailures: number;
2611
+ readonly arm: (apiName: string) => () => void;
2612
+ };
2613
+ }
2614
+
2318
2615
  /** The tags in `P` whose procedure is of kind `K`. */
2319
2616
  export declare type TagsOfKind<P extends ProcedureTypeMap, K extends string> = {
2320
2617
  [T in keyof P]: P[T] extends {
@@ -2727,7 +3024,7 @@ export declare const usePermissions: () => PermissionState_2;
2727
3024
  * @param options `{ skip }` — defers the subscription. `initialSnapshot`
2728
3025
  * comes from the preload payload, not from here.
2729
3026
  */
2730
- export declare function usePreloadedSubscription<T = unknown>(apiName: string, rpcTag: string, input?: Readonly<Record<string, unknown>>, options?: PreloadedSubscriptionOptions): SubscriptionState<T> | SubscriptionIdle;
3027
+ export declare function usePreloadedSubscription<T = unknown>(apiName: string, rpcTag: string, input?: Readonly<Record<string, unknown>>, options?: PreloadedSubscriptionOptions): PreloadedSubscriptionState<T>;
2731
3028
 
2732
3029
  export declare const usePreview: <Input = Record<string, unknown>>(apiName: string, previewTag: string) => PreviewState<Input>;
2733
3030