/** * Svelte 5 live-query bindings for `@happyvertical/smrt-web` (#1761, slice A). * * Turns a SMRT-owned {@link SmrtWebCollection} into runes-reactive live-query * state plus mutation helpers, so a consumer writes reactive components WITHOUT * importing TanStack. The client-data engine (`@tanstack/db` + * `@tanstack/svelte-db`) is used only inside this module — its types never * appear on the public surface, mirroring smrt-web's own engine-absorption * boundary (ratified condition for #1761). * * Two engine facts drive the shape of this file: * * 1. `useLiveQuery` internally uses `$state`/`$derived`/`$effect`, so it (and * therefore {@link liveCollection}) MUST be called during Svelte component * initialization — exactly like this package's other `use*` composables. * Its internal `$effect` binds to the calling component's lifecycle, so the * live subscription is torn down automatically when the component unmounts. * * 2. `@tanstack/svelte-db` live-query rows carry ENUMERABLE engine virtual * props (`$key`/`$origin`/`$synced`/`$collectionId`) that would otherwise * escape through spread or JSON. Every exposed row is projected to a plain * DTO by stripping `$`-prefixed keys (the `$` prefix is reserved for the * engine; SMRT columns never begin with it), mirroring smrt-web's internal * `toPlainRow`. */ import { type SmrtWebCollection, type SmrtWebRow } from '@happyvertical/smrt-web'; /** * Lifecycle status of a {@link LiveCollection}'s underlying read. * * - `loading` — the first load has not completed yet (also covers the engine's * pre-start `idle` and post-teardown `cleaned-up` phases). * - `ready` — data has arrived and the collection is live. * - `error` — the read failed during sync initialization. */ export type LiveCollectionStatus = 'loading' | 'ready' | 'error'; /** * A live, runes-reactive view over a {@link SmrtWebCollection}. Read `rows`, * `status`, and `error` directly in markup — they update as the collection * changes. Do NOT destructure this object (Svelte 5 reactivity is lost on * destructure); read through the object, e.g. `view.rows`, or wrap in * `$derived`. */ export interface LiveCollection { /** Live rows as plain DTOs (no `$`-prefixed engine props), insertion order. */ readonly rows: ReadonlyArray>; /** Coarse lifecycle status of the underlying read. */ readonly status: LiveCollectionStatus; /** * The most recent error surfaced by the underlying read, or `null`. Mutation * errors are surfaced on the {@link LiveCollectionMutation} returned by the * mutation helpers, not here. */ readonly error: unknown; /** True while the first load has not completed (`status === 'loading'`). */ readonly isLoading: boolean; /** True once data has arrived (`status === 'ready'`). */ readonly isReady: boolean; /** True when the underlying read failed (`status === 'error'`). */ readonly isError: boolean; /** * Optimistically insert a row and persist it through the collection's create * surface. The row is visible in `rows` synchronously; the returned handle's * reactive `pending`/`error` track the server outcome and a failed create * rolls the optimistic row back automatically. */ insert(row: SmrtWebRow): LiveCollectionMutation; } /** * Reactive handle to one in-flight mutation. Read `pending`/`error`/`settled` * in markup to drive optimistic UI; await {@link done} to observe completion * imperatively. All fields are SMRT-owned — no engine transaction leaks. */ export interface LiveCollectionMutation { /** True while the write is persisting; flips to false on success or failure. */ readonly pending: boolean; /** True once the write has settled (persisted or rolled back). */ readonly settled: boolean; /** The rollback error if the write failed, else `null`. */ readonly error: unknown; /** * Resolves when the write settles (persisted or rolled back); read * {@link error} (or {@link settled}) for the outcome. Never rejects, so * reactive-only consumers never risk an unhandled rejection. */ readonly done: Promise; } /** Options for {@link liveCollection}. Reserved for forward-compatible growth. */ export interface LiveCollectionOptions { /** * Trigger the collection's first load eagerly when the binding is created, * rather than waiting for the engine's first read. Defaults to `true`. */ preload?: boolean; } /** * Create a runes-reactive live view over a {@link SmrtWebCollection}. * * MUST be called during Svelte component initialization (it delegates to * `@tanstack/svelte-db`'s `useLiveQuery`, which sets up a `$effect`). The live * subscription is torn down automatically when the calling component unmounts. * * @example * ```svelte * * * {#if view.isLoading} *

Loading…

* {:else if view.isError} *

Failed: {String(view.error)}

* {:else} *
    * {#each view.rows as row (row.id)} *
  • {row.name}
  • * {/each} *
* {/if} * ``` * * @example * SvelteKit hydration seeding (#1761): fetch rows in a server load and pass * them as `initialData` so the first client render serves them with NO * duplicate fetch. The live view starts populated at `ready`. * ```ts * // +page.server.ts — read the collection server-side, return plain rows. * import { getCollection } from '../lib/server/smrt'; * import type { PageServerLoad } from './$types'; * * export const load: PageServerLoad = async () => { * const products = await getCollection('Product'); * const rows = await products.list({ limit: 50 }); * return { products: rows.map((p) => ({ id: p.id, name: p.name })) }; * }; * ``` * ```svelte * * * *
    * {#each view.rows as row (row.id)} *
  • {row.name}
  • * {/each} *
* ``` */ export declare function liveCollection(handle: SmrtWebCollection, options?: LiveCollectionOptions): LiveCollection; //# sourceMappingURL=live-collection.svelte.d.ts.map