@korajs/svelte 1.0.0-beta.12 → 1.0.0-beta.13

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/README.md CHANGED
@@ -1,17 +1,18 @@
1
1
  # @korajs/svelte
2
2
 
3
- Svelte bindings for [Kora.js](https://github.com/ehoneahobed/kora) offline-first applications (Svelte 4 stores + Svelte 5 components).
3
+ Svelte bindings for [Kora.js](https://korajs.dev) offline-first applications (Svelte 4 stores + Svelte 5 components).
4
4
 
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- pnpm add korajs @korajs/svelte
8
+ pnpm add korajs@beta @korajs/svelte@beta
9
9
  ```
10
10
 
11
11
  ## Setup
12
12
 
13
13
  Create the Kora app at module scope, connect sync after `ready`, then mount a root layout with provider components (matches the CLI `svelte-sync` template):
14
14
 
15
+ <!-- docs-check: skip template excerpt: imports the project's own auth and schema modules -->
15
16
  ```typescript
16
17
  // main.ts
17
18
  import { createKoraAuthSync } from '@korajs/auth'
@@ -24,7 +25,7 @@ import koraWorkerUrl from './kora-worker.ts?worker&url'
24
25
 
25
26
  const kora = createKoraApp({
26
27
  schema,
27
- sync: { url: 'ws://localhost:3000/kora-sync', authClient: createKoraAuthSync({ authClient, schema }) },
28
+ sync: { url: 'ws://localhost:3001/kora-sync', authClient: createKoraAuthSync({ authClient, schema }) },
28
29
  store: { workerUrl: koraWorkerUrl },
29
30
  })
30
31
 
@@ -54,7 +55,7 @@ Precompiled component JS is also published under `dist/components/` for non-Vite
54
55
 
55
56
  ## Queries
56
57
 
57
- ### Static filters — readable store
58
+ ### Static filters: a readable store
58
59
 
59
60
  ```svelte
60
61
  <script lang="ts">
@@ -69,7 +70,7 @@ Precompiled component JS is also published under `dist/components/` for non-Vite
69
70
  {/each}
70
71
  ```
71
72
 
72
- ### Reactive filters — `KoraQuery` component
73
+ ### Reactive filters: the `KoraQuery` component
73
74
 
74
75
  ```svelte
75
76
  <script lang="ts">
@@ -98,7 +99,7 @@ Precompiled component JS is also published under `dist/components/` for non-Vite
98
99
  | `createSyncStatusStore()` | Sync status readable store |
99
100
  | `getApp()` / `getCollection()` | Context accessors |
100
101
  | `createRichTextBinding()` / `useRichText()` | Yjs richtext editor binding |
101
- | `applyPresence(user)` | Set local presence — use in `$effect(() => applyPresence(user))` |
102
+ | `applyPresence(user)` | Set local presence; use it in `$effect(() => applyPresence(user))` |
102
103
  | `createCollaboratorsStore()` | Remote collaborator awareness states |
103
104
  | `KoraQuery.svelte` | Descriptor-reactive query snippet |
104
105
 
package/dist/index.cjs CHANGED
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  applyPresence: () => applyPresence,
24
24
  createCollaboratorsStore: () => createCollaboratorsStore,
25
25
  createMutation: () => createMutation,
26
+ createQueryStateStore: () => createQueryStateStore,
26
27
  createQueryStore: () => createQueryStore,
27
28
  createRichTextBinding: () => createRichTextBinding,
28
29
  createSyncStatusStore: () => createSyncStatusStore,
@@ -39,6 +40,7 @@ __export(index_exports, {
39
40
  useMutation: () => useMutation,
40
41
  usePresence: () => usePresence,
41
42
  useQuery: () => useQuery,
43
+ useQueryState: () => useQueryState,
42
44
  useRichText: () => useRichText,
43
45
  useSyncStatus: () => useSyncStatus
44
46
  });
@@ -48,8 +50,8 @@ module.exports = __toCommonJS(index_exports);
48
50
  var import_core = require("@korajs/core");
49
51
  var import_store = require("@korajs/store");
50
52
  var import_svelte = require("svelte");
51
- var koraContextKey = /* @__PURE__ */ Symbol("korajs-context");
52
- var koraAppContextKey = /* @__PURE__ */ Symbol("korajs-app");
53
+ var koraContextKey = /* @__PURE__ */ Symbol.for("@korajs/svelte:context");
54
+ var koraAppContextKey = /* @__PURE__ */ Symbol.for("@korajs/svelte:app");
53
55
  function setKoraContext(value) {
54
56
  (0, import_svelte.setContext)(koraContextKey, value);
55
57
  }
@@ -97,28 +99,116 @@ async function initKoraProvider(app) {
97
99
  var import_store2 = require("@korajs/store");
98
100
  var import_store3 = require("svelte/store");
99
101
  var EMPTY_ARRAY = Object.freeze([]);
100
- function createQueryStore(query, options) {
101
- const { queryStoreCache } = getKoraContext();
102
- const enabled = options?.enabled !== false;
103
- return (0, import_store3.readable)(EMPTY_ARRAY, (set) => {
104
- if (!enabled) {
105
- set(EMPTY_ARRAY);
106
- return () => {
107
- };
102
+ function isQueryBuilder(input) {
103
+ return typeof input.getDescriptor === "function";
104
+ }
105
+ function isReadable(input) {
106
+ return typeof input === "object" && input !== null && typeof input.subscribe === "function";
107
+ }
108
+ function readQueryError(queryStore) {
109
+ const channel = queryStore;
110
+ return typeof channel.getError === "function" ? channel.getError() : null;
111
+ }
112
+ function followQuery(cache, query, options, emit) {
113
+ let current = isQueryBuilder(query) ? query : null;
114
+ const enabledInput = options?.enabled;
115
+ let enabled = isReadable(enabledInput) ? true : enabledInput !== false;
116
+ let activeKey = null;
117
+ let release = null;
118
+ let state = {
119
+ data: EMPTY_ARRAY,
120
+ error: null,
121
+ ready: false
122
+ };
123
+ const publish = (next) => {
124
+ if (next.data === state.data && next.error === state.error && next.ready === state.ready) {
125
+ return;
108
126
  }
109
- (0, import_store2.assertQueryReady)(query);
110
- const queryStore = queryStoreCache.getOrCreate(query);
111
- const unsubscribe = queryStore.subscribe(() => {
112
- set(queryStore.getSnapshot());
113
- });
114
- set(queryStore.getSnapshot());
115
- return () => {
127
+ if (next.error && next.error !== state.error) options?.onError?.(next.error);
128
+ state = next;
129
+ emit(state);
130
+ };
131
+ const apply = () => {
132
+ const key = enabled && current ? (0, import_store2.queryKey)(current.getDescriptor()) : null;
133
+ if (key === activeKey) return;
134
+ release?.();
135
+ release = null;
136
+ activeKey = key;
137
+ if (!key || !current) {
138
+ publish({ data: EMPTY_ARRAY, error: null, ready: false });
139
+ return;
140
+ }
141
+ const builder = current;
142
+ (0, import_store2.assertQueryReady)(builder);
143
+ const queryStore = cache.getOrCreate(builder);
144
+ const sync = () => {
145
+ const loaded = queryStore.hasSnapshot();
146
+ publish({
147
+ // A descriptor switch keeps the previous rows until the new query answers.
148
+ data: loaded ? queryStore.getSnapshot() : state.data,
149
+ error: readQueryError(queryStore),
150
+ ready: loaded
151
+ });
152
+ };
153
+ const unsubscribe = queryStore.subscribe(sync);
154
+ sync();
155
+ release = () => {
116
156
  unsubscribe();
117
- queryStoreCache.release(query);
157
+ cache.release(builder);
118
158
  };
119
- });
159
+ };
160
+ const stops = [];
161
+ if (!isQueryBuilder(query)) {
162
+ stops.push(
163
+ query.subscribe((next) => {
164
+ current = next ?? null;
165
+ apply();
166
+ })
167
+ );
168
+ }
169
+ if (isReadable(enabledInput)) {
170
+ stops.push(
171
+ enabledInput.subscribe((next) => {
172
+ enabled = next !== false;
173
+ apply();
174
+ })
175
+ );
176
+ }
177
+ apply();
178
+ return () => {
179
+ for (const stop of stops) stop();
180
+ release?.();
181
+ release = null;
182
+ activeKey = null;
183
+ };
184
+ }
185
+ function createQueryStore(query, options) {
186
+ const { queryStoreCache } = getKoraContext();
187
+ const reporting = {
188
+ ...options,
189
+ onError: options?.onError ?? ((failure) => {
190
+ reportUnhandled(failure);
191
+ })
192
+ };
193
+ return (0, import_store3.readable)(
194
+ EMPTY_ARRAY,
195
+ (set) => followQuery(queryStoreCache, query, reporting, (state) => set(state.data))
196
+ );
197
+ }
198
+ function createQueryStateStore(query, options) {
199
+ const { queryStoreCache } = getKoraContext();
200
+ const initial = { data: EMPTY_ARRAY, error: null, ready: false };
201
+ return (0, import_store3.readable)(
202
+ initial,
203
+ (set) => followQuery(queryStoreCache, query, options, set)
204
+ );
205
+ }
206
+ function reportUnhandled(failure) {
207
+ const host = globalThis;
208
+ host.console?.error("[Kora] createQueryStore failed:", failure);
120
209
  }
121
210
  var useQuery = createQueryStore;
211
+ var useQueryState = createQueryStateStore;
122
212
 
123
213
  // src/composables/use-mutation.ts
124
214
  var import_bindings = require("@korajs/core/bindings");
@@ -334,6 +424,7 @@ var useCollaborators = createCollaboratorsStore;
334
424
  applyPresence,
335
425
  createCollaboratorsStore,
336
426
  createMutation,
427
+ createQueryStateStore,
337
428
  createQueryStore,
338
429
  createRichTextBinding,
339
430
  createSyncStatusStore,
@@ -350,6 +441,7 @@ var useCollaborators = createCollaboratorsStore;
350
441
  useMutation,
351
442
  usePresence,
352
443
  useQuery,
444
+ useQueryState,
353
445
  useRichText,
354
446
  useSyncStatus
355
447
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/context.ts","../src/stores/query-store.ts","../src/composables/use-mutation.ts","../src/composables/use-sync-status.ts","../src/composables/use-app.ts","../src/composables/use-collection.ts","../src/composables/use-rich-text.ts","../src/composables/use-presence.ts","../src/composables/use-collaborators.ts"],"sourcesContent":["export type {\n\tKoraAppHandle,\n\tKoraAppLike,\n\tKoraContextValue,\n\tUseMutationOptions,\n\tUseMutationResult,\n\tUseQueryOptions,\n\tUseRichTextResult,\n} from './types'\n\nexport {\n\tgetKoraApp,\n\tgetKoraContext,\n\tinitKoraProvider,\n\tsetKoraAppContext,\n\tsetKoraContext,\n} from './context'\n\nexport { createQueryStore, useQuery } from './stores/query-store'\nexport { createMutation, useMutation } from './composables/use-mutation'\nexport { createSyncStatusStore, useSyncStatus } from './composables/use-sync-status'\nexport { getApp, useApp } from './composables/use-app'\nexport { getCollection, useCollection } from './composables/use-collection'\nexport { createRichTextBinding, useRichText } from './composables/use-rich-text'\nexport type { UseRichTextOptions } from './composables/use-rich-text'\nexport { applyPresence, usePresence } from './composables/use-presence'\nexport { createCollaboratorsStore, useCollaborators } from './composables/use-collaborators'\n","import { KoraError } from '@korajs/core'\nimport { QueryStoreCache } from '@korajs/store'\nimport { getContext, setContext } from 'svelte'\nimport type { KoraAppLike, KoraContextValue } from './types'\n\nconst koraContextKey = Symbol('korajs-context')\nconst koraAppContextKey = Symbol('korajs-app')\n\nexport function setKoraContext(value: KoraContextValue): void {\n\tsetContext(koraContextKey, value)\n}\n\nexport function getKoraContext(): KoraContextValue {\n\tconst context = getContext<KoraContextValue | undefined>(koraContextKey)\n\tif (!context) {\n\t\tthrow new KoraError(\n\t\t\t'Kora context missing. Wrap your app with <KoraProvider app={kora}> or <KoraStoreProvider store={store}>.',\n\t\t\t'KORA_NOT_PROVIDED',\n\t\t\t{ fix: 'Wrap your app with <KoraProvider app={kora}> or <KoraStoreProvider store={store}>.' },\n\t\t)\n\t}\n\treturn context\n}\n\n/** @deprecated Use {@link setKoraContext} via {@link KoraProvider} or {@link KoraStoreProvider}. */\nexport function setKoraAppContext(koraApp: KoraAppLike): void {\n\tsetContext(koraAppContextKey, koraApp)\n}\n\n/** @deprecated Use {@link getKoraContext} and {@link getApp}. */\nexport function getKoraApp(): KoraAppLike {\n\tconst app = getContext<KoraAppLike | undefined>(koraAppContextKey)\n\tif (!app) {\n\t\tthrow new KoraError(\n\t\t\t'getKoraApp() requires setKoraAppContext(koraApp) on an ancestor.',\n\t\t\t'KORA_NOT_PROVIDED',\n\t\t)\n\t}\n\treturn app\n}\n\n/**\n * Initialize Kora provider context after `app.ready`.\n *\n * @deprecated Prefer {@link KoraProvider} or {@link KoraStoreProvider} in root layout.\n */\nexport async function initKoraProvider(app: KoraAppLike): Promise<KoraContextValue> {\n\tawait app.ready\n\tconst queryStoreCache =\n\t\ttypeof app.getQueryStoreCache === 'function' ? app.getQueryStoreCache() : new QueryStoreCache()\n\tconst value: KoraContextValue = {\n\t\tstore: app.getStore(),\n\t\tsyncEngine: app.getSyncEngine(),\n\t\tapp,\n\t\tevents: app.events ?? null,\n\t\tsubscribeSyncStatus: app.sync?.subscribeStatus ?? null,\n\t\tqueryStoreCache,\n\t}\n\tsetKoraContext(value)\n\tsetKoraAppContext(app)\n\treturn value\n}\n","import type { CollectionRecord, QueryBuilder } from '@korajs/store'\nimport { assertQueryReady } from '@korajs/store'\nimport { type Readable, readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\nimport type { UseQueryOptions } from '../types'\n\nconst EMPTY_ARRAY: readonly unknown[] = Object.freeze([])\n\n/**\n * Create a Svelte readable store for a static Kora query.\n *\n * For reactive filter changes, use {@link KoraQuery} which re-subscribes when the\n * query descriptor changes.\n */\nexport function createQueryStore<T = CollectionRecord>(\n\tquery: QueryBuilder<T>,\n\toptions?: UseQueryOptions,\n): Readable<readonly T[]> {\n\tconst { queryStoreCache } = getKoraContext()\n\tconst enabled = options?.enabled !== false\n\n\treturn readable<readonly T[]>(EMPTY_ARRAY as readonly T[], (set) => {\n\t\tif (!enabled) {\n\t\t\tset(EMPTY_ARRAY as readonly T[])\n\t\t\treturn () => {}\n\t\t}\n\n\t\tassertQueryReady(query as QueryBuilder<unknown>)\n\t\tconst queryStore = queryStoreCache.getOrCreate(query)\n\t\tconst unsubscribe = queryStore.subscribe(() => {\n\t\t\tset(queryStore.getSnapshot())\n\t\t})\n\t\tset(queryStore.getSnapshot())\n\n\t\treturn () => {\n\t\t\tunsubscribe()\n\t\t\tqueryStoreCache.release(query as QueryBuilder<unknown>)\n\t\t}\n\t})\n}\n\n/** Alias for {@link createQueryStore}. */\nexport const useQuery = createQueryStore\n","import { createMutationController } from '@korajs/core/bindings'\nimport { onDestroy } from 'svelte'\nimport type { UseMutationOptions, UseMutationResult } from '../types'\n\n/**\n * Create a mutation controller with optimistic update hooks.\n */\nexport function createMutation<TData, TArgs extends unknown[], TContext = void>(\n\tmutationFn: (...args: TArgs) => Promise<TData>,\n\toptions?: UseMutationOptions<TData, TArgs, TContext>,\n): UseMutationResult<TData, TArgs> {\n\tconst optionsRef = { current: options }\n\toptionsRef.current = options\n\n\tconst fnRef = { current: mutationFn }\n\tfnRef.current = mutationFn\n\n\tconst controller = createMutationController<TData, TArgs, TContext>({\n\t\tmutationFn: (...args) => fnRef.current(...args),\n\t\tresolveOptions: () => optionsRef.current,\n\t})\n\n\tconst loadingListeners = new Set<(value: boolean) => void>()\n\tconst errorListeners = new Set<(value: Error | null) => void>()\n\n\tconst unsubscribe = controller.subscribe(() => {\n\t\tconst snapshot = controller.getSnapshot()\n\t\tfor (const listener of loadingListeners) {\n\t\t\tlistener(snapshot.isLoading)\n\t\t}\n\t\tfor (const listener of errorListeners) {\n\t\t\tlistener(snapshot.error)\n\t\t}\n\t})\n\n\t// Dispose the controller when the owning component unmounts, matching the\n\t// React (`useController`) and Vue (`onScopeDispose`) lifecycles. Guarded so\n\t// `createMutation()` can still be called outside a component (manual usage),\n\t// where `onDestroy` is unavailable and the caller owns disposal.\n\ttry {\n\t\tonDestroy(() => {\n\t\t\tunsubscribe()\n\t\t\tcontroller.destroy()\n\t\t})\n\t} catch {\n\t\t// Not inside a component initialization — no lifecycle to hook into.\n\t}\n\n\treturn {\n\t\tmutate: (...args: TArgs) => controller.mutate(...args),\n\t\tmutateAsync: (...args: TArgs) => controller.mutateAsync(...args),\n\t\tsubscribeLoading: (fn) => {\n\t\t\tloadingListeners.add(fn)\n\t\t\tfn(controller.getSnapshot().isLoading)\n\t\t\treturn () => loadingListeners.delete(fn)\n\t\t},\n\t\tsubscribeError: (fn) => {\n\t\t\terrorListeners.add(fn)\n\t\t\tfn(controller.getSnapshot().error)\n\t\t\treturn () => errorListeners.delete(fn)\n\t\t},\n\t\tget loading() {\n\t\t\treturn controller.getSnapshot().isLoading\n\t\t},\n\t\tget isLoading() {\n\t\t\treturn controller.getSnapshot().isLoading\n\t\t},\n\t\tget error() {\n\t\t\treturn controller.getSnapshot().error\n\t\t},\n\t\treset: () => controller.reset(),\n\t}\n}\n\n/** Alias for {@link createMutation}. */\nexport const useMutation = createMutation\n","import { OFFLINE_SYNC_STATUS, createSyncStatusController } from '@korajs/sync'\nimport type { SyncStatusInfo } from '@korajs/sync'\nimport { type Readable, readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\n\n/**\n * Readable store of sync engine status.\n */\nexport function createSyncStatusStore(): Readable<SyncStatusInfo> {\n\tconst { syncEngine, subscribeSyncStatus, events } = getKoraContext()\n\n\treturn readable<SyncStatusInfo>(OFFLINE_SYNC_STATUS, (set) => {\n\t\tconst controller = createSyncStatusController({\n\t\t\tsyncEngine,\n\t\t\tsubscribeSyncStatus,\n\t\t\tevents: subscribeSyncStatus ? null : events,\n\t\t})\n\t\tset(controller.getSnapshot())\n\t\tconst unsubscribe = controller.subscribe(() => {\n\t\t\tset(controller.getSnapshot())\n\t\t})\n\t\treturn () => {\n\t\t\tunsubscribe()\n\t\t\tcontroller.destroy()\n\t\t}\n\t})\n}\n\n/** Alias for {@link createSyncStatusStore}. */\nexport const useSyncStatus = createSyncStatusStore\n","import { getKoraContext } from '../context'\nimport type { KoraAppLike } from '../types'\n\nexport function getApp<T extends KoraAppLike = KoraAppLike>(): T {\n\tconst { app } = getKoraContext()\n\tif (!app) {\n\t\tthrow new Error(\n\t\t\t'getApp() requires <KoraProvider app={kora}> or <KoraStoreProvider store={store}> with a createApp() instance.',\n\t\t)\n\t}\n\treturn app as T\n}\n\n/** Alias for {@link getApp}. */\nexport const useApp = getApp\n","import type { CollectionAccessor } from '@korajs/store'\nimport { getKoraContext } from '../context'\n\nexport function getCollection(name: string): CollectionAccessor {\n\tconst { store } = getKoraContext()\n\treturn store.collection(name)\n}\n\n/** Alias for {@link getCollection}. */\nexport const useCollection = getCollection\n","import { asRichTextSyncEngine, createRichTextController } from '@korajs/store'\nimport type { AwarenessUser } from '@korajs/sync'\nimport { onDestroy } from 'svelte'\nimport { type Readable, get, readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\nimport type { UseRichTextResult } from '../types'\n\nexport interface UseRichTextOptions {\n\tuser?: AwarenessUser\n\tuseDocChannel?: boolean\n}\n\n/**\n * Binds a richtext field to a shared Yjs document for editor integration.\n *\n * Must be called during component initialization. For reactive target changes,\n * use {@link KoraRichText} instead.\n */\nexport function createRichTextBinding(\n\tcollectionName: string,\n\trecordId: string,\n\tfieldName: string,\n\toptions?: UseRichTextOptions,\n): UseRichTextResult & { subscribe: Readable<UseRichTextResult>['subscribe'] } {\n\tconst { store, syncEngine } = getKoraContext()\n\n\tconst controller = createRichTextController({\n\t\tcollection: store.collection(collectionName),\n\t\tcollectionName,\n\t\trecordId,\n\t\tfieldName,\n\t\tstore,\n\t\tsyncEngine: asRichTextSyncEngine(syncEngine),\n\t\tuseDocChannel: options?.useDocChannel,\n\t\tuser: options?.user,\n\t})\n\n\tonDestroy(() => {\n\t\tcontroller.destroy()\n\t})\n\n\tconst resultStore = readable<UseRichTextResult>(buildResult(controller), (set) => {\n\t\tconst sync = (): void => {\n\t\t\tset(buildResult(controller))\n\t\t}\n\t\tsync()\n\t\treturn controller.subscribe(sync)\n\t})\n\n\treturn {\n\t\tget doc() {\n\t\t\treturn controller.doc\n\t\t},\n\t\tget text() {\n\t\t\treturn controller.text\n\t\t},\n\t\tundo: () => controller.undo(),\n\t\tredo: () => controller.redo(),\n\t\tget ready() {\n\t\t\treturn get(resultStore).ready\n\t\t},\n\t\tget error() {\n\t\t\treturn get(resultStore).error\n\t\t},\n\t\tget canUndo() {\n\t\t\treturn get(resultStore).canUndo\n\t\t},\n\t\tget canRedo() {\n\t\t\treturn get(resultStore).canRedo\n\t\t},\n\t\tget cursors() {\n\t\t\treturn get(resultStore).cursors\n\t\t},\n\t\tsetCursor: (anchor: number, head: number) => controller.setCursor(anchor, head),\n\t\tclearCursor: () => controller.clearCursor(),\n\t\tsubscribe: resultStore.subscribe,\n\t}\n}\n\n/** @alias createRichTextBinding */\nexport const useRichText = createRichTextBinding\n\nfunction buildResult(controller: ReturnType<typeof createRichTextController>): UseRichTextResult {\n\tconst snapshot = controller.getSnapshot()\n\treturn {\n\t\tdoc: controller.doc,\n\t\ttext: controller.text,\n\t\tundo: () => controller.undo(),\n\t\tredo: () => controller.redo(),\n\t\tready: snapshot.ready,\n\t\terror: snapshot.error,\n\t\tcanUndo: snapshot.canUndo,\n\t\tcanRedo: snapshot.canRedo,\n\t\tcursors: [...snapshot.cursors],\n\t\tsetCursor: (anchor, head) => controller.setCursor(anchor, head),\n\t\tclearCursor: () => controller.clearCursor(),\n\t}\n}\n","import { getKoraContext } from '../context'\n\n/**\n * Applies local collaborative presence. Returns a cleanup function.\n *\n * In Svelte components, call from an effect:\n * `$effect(() => applyPresence(user))`\n */\nexport function applyPresence(\n\tuser: { name: string; color: string; avatar?: string } | null,\n): () => void {\n\tconst { syncEngine } = getKoraContext()\n\tif (!syncEngine || !user?.name || !user?.color) {\n\t\treturn () => {}\n\t}\n\n\tconst awareness = syncEngine.getAwarenessManager()\n\tawareness.setLocalState({\n\t\tuser: {\n\t\t\tname: user.name,\n\t\t\tcolor: user.color,\n\t\t\tavatar: user.avatar,\n\t\t},\n\t})\n\n\treturn () => {\n\t\tawareness.setLocalState(null)\n\t}\n}\n\n/** Alias for {@link applyPresence} — use inside `$effect()` in `.svelte` files. */\nexport const usePresence = applyPresence\n","import type { AwarenessState } from '@korajs/sync'\nimport { subscribeRemoteAwarenessStates } from '@korajs/sync'\nimport { type Readable, readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\n\n/**\n * Readable store of remote collaborators' awareness states.\n */\nexport function createCollaboratorsStore(): Readable<AwarenessState[]> {\n\tconst { syncEngine } = getKoraContext()\n\n\treturn readable<AwarenessState[]>([], (set) => {\n\t\tif (!syncEngine) {\n\t\t\tset([])\n\t\t\treturn () => {}\n\t\t}\n\n\t\tconst awareness = syncEngine.getAwarenessManager()\n\t\treturn subscribeRemoteAwarenessStates(awareness, set)\n\t})\n}\n\n/** Alias for {@link createCollaboratorsStore}. */\nexport const useCollaborators = createCollaboratorsStore\n"],"mappings":"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","names":["import_store","import_svelte","import_store","import_store","import_svelte","import_sync","import_store"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/context.ts","../src/stores/query-store.ts","../src/composables/use-mutation.ts","../src/composables/use-sync-status.ts","../src/composables/use-app.ts","../src/composables/use-collection.ts","../src/composables/use-rich-text.ts","../src/composables/use-presence.ts","../src/composables/use-collaborators.ts"],"sourcesContent":["export type {\n\tKoraAppHandle,\n\tKoraAppLike,\n\tKoraContextValue,\n\tUseMutationOptions,\n\tUseMutationResult,\n\tQueryState,\n\tUseQueryOptions,\n\tUseRichTextResult,\n} from './types'\n\nexport {\n\tgetKoraApp,\n\tgetKoraContext,\n\tinitKoraProvider,\n\tsetKoraAppContext,\n\tsetKoraContext,\n} from './context'\n\nexport {\n\tcreateQueryStateStore,\n\tcreateQueryStore,\n\tuseQuery,\n\tuseQueryState,\n} from './stores/query-store'\nexport type { QueryInput } from './stores/query-store'\nexport { createMutation, useMutation } from './composables/use-mutation'\nexport { createSyncStatusStore, useSyncStatus } from './composables/use-sync-status'\nexport { getApp, useApp } from './composables/use-app'\nexport { getCollection, useCollection } from './composables/use-collection'\nexport { createRichTextBinding, useRichText } from './composables/use-rich-text'\nexport type { UseRichTextOptions } from './composables/use-rich-text'\nexport { applyPresence, usePresence } from './composables/use-presence'\nexport { createCollaboratorsStore, useCollaborators } from './composables/use-collaborators'\n","import { KoraError } from '@korajs/core'\nimport { QueryStoreCache } from '@korajs/store'\nimport { getContext, setContext } from 'svelte'\nimport type { KoraAppLike, KoraContextValue } from './types'\n\n// Registered (Symbol.for) keys: the .svelte components are compiled from src/ by the app\n// (the \"svelte\" export condition) while helpers such as getCollection come from dist/, so\n// two copies of this module exist in every app. Module-local Symbol() keys made the\n// provider's context invisible to the helpers (\"Kora context missing\").\nconst koraContextKey = Symbol.for('@korajs/svelte:context')\nconst koraAppContextKey = Symbol.for('@korajs/svelte:app')\n\nexport function setKoraContext(value: KoraContextValue): void {\n\tsetContext(koraContextKey, value)\n}\n\nexport function getKoraContext(): KoraContextValue {\n\tconst context = getContext<KoraContextValue | undefined>(koraContextKey)\n\tif (!context) {\n\t\tthrow new KoraError(\n\t\t\t'Kora context missing. Wrap your app with <KoraProvider app={kora}> or <KoraStoreProvider store={store}>.',\n\t\t\t'KORA_NOT_PROVIDED',\n\t\t\t{ fix: 'Wrap your app with <KoraProvider app={kora}> or <KoraStoreProvider store={store}>.' },\n\t\t)\n\t}\n\treturn context\n}\n\n/** @deprecated Use {@link setKoraContext} via {@link KoraProvider} or {@link KoraStoreProvider}. */\nexport function setKoraAppContext(koraApp: KoraAppLike): void {\n\tsetContext(koraAppContextKey, koraApp)\n}\n\n/** @deprecated Use {@link getKoraContext} and {@link getApp}. */\nexport function getKoraApp(): KoraAppLike {\n\tconst app = getContext<KoraAppLike | undefined>(koraAppContextKey)\n\tif (!app) {\n\t\tthrow new KoraError(\n\t\t\t'getKoraApp() requires setKoraAppContext(koraApp) on an ancestor.',\n\t\t\t'KORA_NOT_PROVIDED',\n\t\t)\n\t}\n\treturn app\n}\n\n/**\n * Initialize Kora provider context after `app.ready`.\n *\n * @deprecated Prefer {@link KoraProvider} or {@link KoraStoreProvider} in root layout.\n */\nexport async function initKoraProvider(app: KoraAppLike): Promise<KoraContextValue> {\n\tawait app.ready\n\tconst queryStoreCache =\n\t\ttypeof app.getQueryStoreCache === 'function' ? app.getQueryStoreCache() : new QueryStoreCache()\n\tconst value: KoraContextValue = {\n\t\tstore: app.getStore(),\n\t\tsyncEngine: app.getSyncEngine(),\n\t\tapp,\n\t\tevents: app.events ?? null,\n\t\tsubscribeSyncStatus: app.sync?.subscribeStatus ?? null,\n\t\tqueryStoreCache,\n\t}\n\tsetKoraContext(value)\n\tsetKoraAppContext(app)\n\treturn value\n}\n","import type { CollectionRecord, QueryBuilder, QueryStore, QueryStoreCache } from '@korajs/store'\nimport { assertQueryReady, queryKey } from '@korajs/store'\nimport { type Readable, readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\nimport type { QueryState, UseQueryOptions } from '../types'\n\nconst EMPTY_ARRAY: readonly unknown[] = Object.freeze([])\n\n/** A query input: a builder, or a readable store of one (null disables). */\nexport type QueryInput<T> = QueryBuilder<T> | Readable<QueryBuilder<T> | null | undefined>\n\nfunction isQueryBuilder<T>(input: QueryInput<T>): input is QueryBuilder<T> {\n\treturn typeof (input as { getDescriptor?: unknown }).getDescriptor === 'function'\n}\n\nfunction isReadable<V>(input: V | Readable<V>): input is Readable<V> {\n\treturn (\n\t\ttypeof input === 'object' &&\n\t\tinput !== null &&\n\t\ttypeof (input as { subscribe?: unknown }).subscribe === 'function'\n\t)\n}\n\n/** The STORE-12 error channel of a QueryStore, read structurally (older store builds lack it). */\nfunction readQueryError(queryStore: QueryStore<unknown>): Error | null {\n\tconst channel = queryStore as unknown as { getError?: () => Error | null }\n\treturn typeof channel.getError === 'function' ? channel.getError() : null\n}\n\n/**\n * Follows the query and `enabled` inputs (values or readable stores), holding one\n * ref-counted QueryStore per descriptor and switching when the descriptor changes\n * (DX-7). Returns the teardown.\n */\nfunction followQuery<T>(\n\tcache: QueryStoreCache,\n\tquery: QueryInput<T>,\n\toptions: UseQueryOptions | undefined,\n\temit: (state: QueryState<T>) => void,\n): () => void {\n\tlet current: QueryBuilder<T> | null = isQueryBuilder(query) ? query : null\n\tconst enabledInput = options?.enabled\n\tlet enabled = isReadable(enabledInput) ? true : enabledInput !== false\n\tlet activeKey: string | null = null\n\tlet release: (() => void) | null = null\n\tlet state: QueryState<T> = {\n\t\tdata: EMPTY_ARRAY as readonly T[],\n\t\terror: null,\n\t\tready: false,\n\t}\n\n\tconst publish = (next: QueryState<T>): void => {\n\t\tif (next.data === state.data && next.error === state.error && next.ready === state.ready) {\n\t\t\treturn\n\t\t}\n\t\tif (next.error && next.error !== state.error) options?.onError?.(next.error)\n\t\tstate = next\n\t\temit(state)\n\t}\n\n\tconst apply = (): void => {\n\t\tconst key = enabled && current ? queryKey(current.getDescriptor()) : null\n\t\tif (key === activeKey) return\n\t\trelease?.()\n\t\trelease = null\n\t\tactiveKey = key\n\t\tif (!key || !current) {\n\t\t\tpublish({ data: EMPTY_ARRAY as readonly T[], error: null, ready: false })\n\t\t\treturn\n\t\t}\n\t\tconst builder = current\n\t\tassertQueryReady(builder as QueryBuilder<unknown>)\n\t\tconst queryStore = cache.getOrCreate(builder)\n\t\tconst sync = (): void => {\n\t\t\tconst loaded = queryStore.hasSnapshot()\n\t\t\tpublish({\n\t\t\t\t// A descriptor switch keeps the previous rows until the new query answers.\n\t\t\t\tdata: loaded ? queryStore.getSnapshot() : state.data,\n\t\t\t\terror: readQueryError(queryStore as QueryStore<unknown>),\n\t\t\t\tready: loaded,\n\t\t\t})\n\t\t}\n\t\tconst unsubscribe = queryStore.subscribe(sync)\n\t\tsync()\n\t\trelease = () => {\n\t\t\tunsubscribe()\n\t\t\tcache.release(builder as QueryBuilder<unknown>)\n\t\t}\n\t}\n\n\tconst stops: Array<() => void> = []\n\tif (!isQueryBuilder(query)) {\n\t\tstops.push(\n\t\t\tquery.subscribe((next) => {\n\t\t\t\tcurrent = next ?? null\n\t\t\t\tapply()\n\t\t\t}),\n\t\t)\n\t}\n\tif (isReadable(enabledInput)) {\n\t\tstops.push(\n\t\t\tenabledInput.subscribe((next) => {\n\t\t\t\tenabled = next !== false\n\t\t\t\tapply()\n\t\t\t}),\n\t\t)\n\t}\n\tapply()\n\n\treturn () => {\n\t\tfor (const stop of stops) stop()\n\t\trelease?.()\n\t\trelease = null\n\t\tactiveKey = null\n\t}\n}\n\n/**\n * Create a Svelte readable store of a Kora query's rows.\n *\n * The query and `enabled` may be plain values or readable stores: pass a store (for\n * example a `derived` of your filter) and the rows follow it, re-subscribing when the\n * query's descriptor changes. A failed query is reported through `options.onError`,\n * or `console.error` without one; use {@link createQueryStateStore} to render it.\n *\n * @param query - A query builder, or a readable store of one (null disables)\n * @param options - `enabled` (value or readable store; default true) and `onError`\n * @returns A readable store of the current rows\n *\n * @example\n * ```ts\n * const filter = writable(false)\n * const todos = createQueryStore(derived(filter, (done) => app.todos.where({ completed: done })))\n * ```\n */\nexport function createQueryStore<T = CollectionRecord>(\n\tquery: QueryInput<T>,\n\toptions?: UseQueryOptions,\n): Readable<readonly T[]> {\n\tconst { queryStoreCache } = getKoraContext()\n\tconst reporting: UseQueryOptions = {\n\t\t...options,\n\t\tonError:\n\t\t\toptions?.onError ??\n\t\t\t((failure: Error) => {\n\t\t\t\t// Never swallowed: without a handler the failure is at least logged.\n\t\t\t\treportUnhandled(failure)\n\t\t\t}),\n\t}\n\treturn readable<readonly T[]>(EMPTY_ARRAY as readonly T[], (set) =>\n\t\tfollowQuery(queryStoreCache, query, reporting, (state) => set(state.data)),\n\t)\n}\n\n/**\n * Like {@link createQueryStore}, but the store holds `{ data, error, ready }`.\n *\n * @param query - A query builder, or a readable store of one\n * @param options - `enabled` and `onError`\n * @returns A readable store of the query state\n */\nexport function createQueryStateStore<T = CollectionRecord>(\n\tquery: QueryInput<T>,\n\toptions?: UseQueryOptions,\n): Readable<QueryState<T>> {\n\tconst { queryStoreCache } = getKoraContext()\n\tconst initial: QueryState<T> = { data: EMPTY_ARRAY as readonly T[], error: null, ready: false }\n\treturn readable<QueryState<T>>(initial, (set) =>\n\t\tfollowQuery(queryStoreCache, query, options, set),\n\t)\n}\n\n/**\n * Logs a query failure nobody handles. Read through globalThis because this package\n * builds without DOM or Node typings.\n */\nfunction reportUnhandled(failure: Error): void {\n\tconst host = globalThis as { console?: { error(...args: unknown[]): void } }\n\thost.console?.error('[Kora] createQueryStore failed:', failure)\n}\n\n/** Alias for {@link createQueryStore}. */\nexport const useQuery = createQueryStore\n\n/** Alias for {@link createQueryStateStore}. */\nexport const useQueryState = createQueryStateStore\n","import { createMutationController } from '@korajs/core/bindings'\nimport { onDestroy } from 'svelte'\nimport type { UseMutationOptions, UseMutationResult } from '../types'\n\n/**\n * Create a mutation controller with optimistic update hooks.\n */\nexport function createMutation<TData, TArgs extends unknown[], TContext = void>(\n\tmutationFn: (...args: TArgs) => Promise<TData>,\n\toptions?: UseMutationOptions<TData, TArgs, TContext>,\n): UseMutationResult<TData, TArgs> {\n\tconst optionsRef = { current: options }\n\toptionsRef.current = options\n\n\tconst fnRef = { current: mutationFn }\n\tfnRef.current = mutationFn\n\n\tconst controller = createMutationController<TData, TArgs, TContext>({\n\t\tmutationFn: (...args) => fnRef.current(...args),\n\t\tresolveOptions: () => optionsRef.current,\n\t})\n\n\tconst loadingListeners = new Set<(value: boolean) => void>()\n\tconst errorListeners = new Set<(value: Error | null) => void>()\n\n\tconst unsubscribe = controller.subscribe(() => {\n\t\tconst snapshot = controller.getSnapshot()\n\t\tfor (const listener of loadingListeners) {\n\t\t\tlistener(snapshot.isLoading)\n\t\t}\n\t\tfor (const listener of errorListeners) {\n\t\t\tlistener(snapshot.error)\n\t\t}\n\t})\n\n\t// Dispose the controller when the owning component unmounts, matching the\n\t// React (`useController`) and Vue (`onScopeDispose`) lifecycles. Guarded so\n\t// `createMutation()` can still be called outside a component (manual usage),\n\t// where `onDestroy` is unavailable and the caller owns disposal.\n\ttry {\n\t\tonDestroy(() => {\n\t\t\tunsubscribe()\n\t\t\tcontroller.destroy()\n\t\t})\n\t} catch {\n\t\t// Not inside a component initialization — no lifecycle to hook into.\n\t}\n\n\treturn {\n\t\tmutate: (...args: TArgs) => controller.mutate(...args),\n\t\tmutateAsync: (...args: TArgs) => controller.mutateAsync(...args),\n\t\tsubscribeLoading: (fn) => {\n\t\t\tloadingListeners.add(fn)\n\t\t\tfn(controller.getSnapshot().isLoading)\n\t\t\treturn () => loadingListeners.delete(fn)\n\t\t},\n\t\tsubscribeError: (fn) => {\n\t\t\terrorListeners.add(fn)\n\t\t\tfn(controller.getSnapshot().error)\n\t\t\treturn () => errorListeners.delete(fn)\n\t\t},\n\t\tget loading() {\n\t\t\treturn controller.getSnapshot().isLoading\n\t\t},\n\t\tget isLoading() {\n\t\t\treturn controller.getSnapshot().isLoading\n\t\t},\n\t\tget error() {\n\t\t\treturn controller.getSnapshot().error\n\t\t},\n\t\treset: () => controller.reset(),\n\t}\n}\n\n/** Alias for {@link createMutation}. */\nexport const useMutation = createMutation\n","import { OFFLINE_SYNC_STATUS, createSyncStatusController } from '@korajs/sync'\nimport type { SyncStatusInfo } from '@korajs/sync'\nimport { type Readable, readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\n\n/**\n * Readable store of sync engine status.\n */\nexport function createSyncStatusStore(): Readable<SyncStatusInfo> {\n\tconst { syncEngine, subscribeSyncStatus, events } = getKoraContext()\n\n\treturn readable<SyncStatusInfo>(OFFLINE_SYNC_STATUS, (set) => {\n\t\tconst controller = createSyncStatusController({\n\t\t\tsyncEngine,\n\t\t\tsubscribeSyncStatus,\n\t\t\tevents: subscribeSyncStatus ? null : events,\n\t\t})\n\t\tset(controller.getSnapshot())\n\t\tconst unsubscribe = controller.subscribe(() => {\n\t\t\tset(controller.getSnapshot())\n\t\t})\n\t\treturn () => {\n\t\t\tunsubscribe()\n\t\t\tcontroller.destroy()\n\t\t}\n\t})\n}\n\n/** Alias for {@link createSyncStatusStore}. */\nexport const useSyncStatus = createSyncStatusStore\n","import { getKoraContext } from '../context'\nimport type { KoraAppLike } from '../types'\n\nexport function getApp<T extends KoraAppLike = KoraAppLike>(): T {\n\tconst { app } = getKoraContext()\n\tif (!app) {\n\t\tthrow new Error(\n\t\t\t'getApp() requires <KoraProvider app={kora}> or <KoraStoreProvider store={store}> with a createApp() instance.',\n\t\t)\n\t}\n\treturn app as T\n}\n\n/** Alias for {@link getApp}. */\nexport const useApp = getApp\n","import type { CollectionAccessor } from '@korajs/store'\nimport { getKoraContext } from '../context'\n\nexport function getCollection(name: string): CollectionAccessor {\n\tconst { store } = getKoraContext()\n\treturn store.collection(name)\n}\n\n/** Alias for {@link getCollection}. */\nexport const useCollection = getCollection\n","import { asRichTextSyncEngine, createRichTextController } from '@korajs/store'\nimport type { AwarenessUser } from '@korajs/sync'\nimport { onDestroy } from 'svelte'\nimport { type Readable, get, readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\nimport type { UseRichTextResult } from '../types'\n\nexport interface UseRichTextOptions {\n\tuser?: AwarenessUser\n\tuseDocChannel?: boolean\n}\n\n/**\n * Binds a richtext field to a shared Yjs document for editor integration.\n *\n * Must be called during component initialization. For reactive target changes,\n * use {@link KoraRichText} instead.\n */\nexport function createRichTextBinding(\n\tcollectionName: string,\n\trecordId: string,\n\tfieldName: string,\n\toptions?: UseRichTextOptions,\n): UseRichTextResult & { subscribe: Readable<UseRichTextResult>['subscribe'] } {\n\tconst { store, syncEngine } = getKoraContext()\n\n\tconst controller = createRichTextController({\n\t\tcollection: store.collection(collectionName),\n\t\tcollectionName,\n\t\trecordId,\n\t\tfieldName,\n\t\tstore,\n\t\tsyncEngine: asRichTextSyncEngine(syncEngine),\n\t\tuseDocChannel: options?.useDocChannel,\n\t\tuser: options?.user,\n\t})\n\n\tonDestroy(() => {\n\t\tcontroller.destroy()\n\t})\n\n\tconst resultStore = readable<UseRichTextResult>(buildResult(controller), (set) => {\n\t\tconst sync = (): void => {\n\t\t\tset(buildResult(controller))\n\t\t}\n\t\tsync()\n\t\treturn controller.subscribe(sync)\n\t})\n\n\treturn {\n\t\tget doc() {\n\t\t\treturn controller.doc\n\t\t},\n\t\tget text() {\n\t\t\treturn controller.text\n\t\t},\n\t\tundo: () => controller.undo(),\n\t\tredo: () => controller.redo(),\n\t\tget ready() {\n\t\t\treturn get(resultStore).ready\n\t\t},\n\t\tget error() {\n\t\t\treturn get(resultStore).error\n\t\t},\n\t\tget canUndo() {\n\t\t\treturn get(resultStore).canUndo\n\t\t},\n\t\tget canRedo() {\n\t\t\treturn get(resultStore).canRedo\n\t\t},\n\t\tget cursors() {\n\t\t\treturn get(resultStore).cursors\n\t\t},\n\t\tsetCursor: (anchor: number, head: number) => controller.setCursor(anchor, head),\n\t\tclearCursor: () => controller.clearCursor(),\n\t\tsubscribe: resultStore.subscribe,\n\t}\n}\n\n/** @alias createRichTextBinding */\nexport const useRichText = createRichTextBinding\n\nfunction buildResult(controller: ReturnType<typeof createRichTextController>): UseRichTextResult {\n\tconst snapshot = controller.getSnapshot()\n\treturn {\n\t\tdoc: controller.doc,\n\t\ttext: controller.text,\n\t\tundo: () => controller.undo(),\n\t\tredo: () => controller.redo(),\n\t\tready: snapshot.ready,\n\t\terror: snapshot.error,\n\t\tcanUndo: snapshot.canUndo,\n\t\tcanRedo: snapshot.canRedo,\n\t\tcursors: [...snapshot.cursors],\n\t\tsetCursor: (anchor, head) => controller.setCursor(anchor, head),\n\t\tclearCursor: () => controller.clearCursor(),\n\t}\n}\n","import { getKoraContext } from '../context'\n\n/**\n * Applies local collaborative presence. Returns a cleanup function.\n *\n * In Svelte components, call from an effect:\n * `$effect(() => applyPresence(user))`\n */\nexport function applyPresence(\n\tuser: { name: string; color: string; avatar?: string } | null,\n): () => void {\n\tconst { syncEngine } = getKoraContext()\n\tif (!syncEngine || !user?.name || !user?.color) {\n\t\treturn () => {}\n\t}\n\n\tconst awareness = syncEngine.getAwarenessManager()\n\tawareness.setLocalState({\n\t\tuser: {\n\t\t\tname: user.name,\n\t\t\tcolor: user.color,\n\t\t\tavatar: user.avatar,\n\t\t},\n\t})\n\n\treturn () => {\n\t\tawareness.setLocalState(null)\n\t}\n}\n\n/** Alias for {@link applyPresence} — use inside `$effect()` in `.svelte` files. */\nexport const usePresence = applyPresence\n","import type { AwarenessState } from '@korajs/sync'\nimport { subscribeRemoteAwarenessStates } from '@korajs/sync'\nimport { type Readable, readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\n\n/**\n * Readable store of remote collaborators' awareness states.\n */\nexport function createCollaboratorsStore(): Readable<AwarenessState[]> {\n\tconst { syncEngine } = getKoraContext()\n\n\treturn readable<AwarenessState[]>([], (set) => {\n\t\tif (!syncEngine) {\n\t\t\tset([])\n\t\t\treturn () => {}\n\t\t}\n\n\t\tconst awareness = syncEngine.getAwarenessManager()\n\t\treturn subscribeRemoteAwarenessStates(awareness, set)\n\t})\n}\n\n/** Alias for {@link createCollaboratorsStore}. */\nexport const useCollaborators = createCollaboratorsStore\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAA0B;AAC1B,mBAAgC;AAChC,oBAAuC;AAOvC,IAAM,iBAAiB,uBAAO,IAAI,wBAAwB;AAC1D,IAAM,oBAAoB,uBAAO,IAAI,oBAAoB;AAElD,SAAS,eAAe,OAA+B;AAC7D,gCAAW,gBAAgB,KAAK;AACjC;AAEO,SAAS,iBAAmC;AAClD,QAAM,cAAU,0BAAyC,cAAc;AACvE,MAAI,CAAC,SAAS;AACb,UAAM,IAAI;AAAA,MACT;AAAA,MACA;AAAA,MACA,EAAE,KAAK,qFAAqF;AAAA,IAC7F;AAAA,EACD;AACA,SAAO;AACR;AAGO,SAAS,kBAAkB,SAA4B;AAC7D,gCAAW,mBAAmB,OAAO;AACtC;AAGO,SAAS,aAA0B;AACzC,QAAM,UAAM,0BAAoC,iBAAiB;AACjE,MAAI,CAAC,KAAK;AACT,UAAM,IAAI;AAAA,MACT;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAOA,eAAsB,iBAAiB,KAA6C;AACnF,QAAM,IAAI;AACV,QAAM,kBACL,OAAO,IAAI,uBAAuB,aAAa,IAAI,mBAAmB,IAAI,IAAI,6BAAgB;AAC/F,QAAM,QAA0B;AAAA,IAC/B,OAAO,IAAI,SAAS;AAAA,IACpB,YAAY,IAAI,cAAc;AAAA,IAC9B;AAAA,IACA,QAAQ,IAAI,UAAU;AAAA,IACtB,qBAAqB,IAAI,MAAM,mBAAmB;AAAA,IAClD;AAAA,EACD;AACA,iBAAe,KAAK;AACpB,oBAAkB,GAAG;AACrB,SAAO;AACR;;;AChEA,IAAAA,gBAA2C;AAC3C,IAAAA,gBAAwC;AAIxC,IAAM,cAAkC,OAAO,OAAO,CAAC,CAAC;AAKxD,SAAS,eAAkB,OAAgD;AAC1E,SAAO,OAAQ,MAAsC,kBAAkB;AACxE;AAEA,SAAS,WAAc,OAA8C;AACpE,SACC,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAAkC,cAAc;AAE1D;AAGA,SAAS,eAAe,YAA+C;AACtE,QAAM,UAAU;AAChB,SAAO,OAAO,QAAQ,aAAa,aAAa,QAAQ,SAAS,IAAI;AACtE;AAOA,SAAS,YACR,OACA,OACA,SACA,MACa;AACb,MAAI,UAAkC,eAAe,KAAK,IAAI,QAAQ;AACtE,QAAM,eAAe,SAAS;AAC9B,MAAI,UAAU,WAAW,YAAY,IAAI,OAAO,iBAAiB;AACjE,MAAI,YAA2B;AAC/B,MAAI,UAA+B;AACnC,MAAI,QAAuB;AAAA,IAC1B,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,EACR;AAEA,QAAM,UAAU,CAAC,SAA8B;AAC9C,QAAI,KAAK,SAAS,MAAM,QAAQ,KAAK,UAAU,MAAM,SAAS,KAAK,UAAU,MAAM,OAAO;AACzF;AAAA,IACD;AACA,QAAI,KAAK,SAAS,KAAK,UAAU,MAAM,MAAO,UAAS,UAAU,KAAK,KAAK;AAC3E,YAAQ;AACR,SAAK,KAAK;AAAA,EACX;AAEA,QAAM,QAAQ,MAAY;AACzB,UAAM,MAAM,WAAW,cAAU,wBAAS,QAAQ,cAAc,CAAC,IAAI;AACrE,QAAI,QAAQ,UAAW;AACvB,cAAU;AACV,cAAU;AACV,gBAAY;AACZ,QAAI,CAAC,OAAO,CAAC,SAAS;AACrB,cAAQ,EAAE,MAAM,aAA6B,OAAO,MAAM,OAAO,MAAM,CAAC;AACxE;AAAA,IACD;AACA,UAAM,UAAU;AAChB,wCAAiB,OAAgC;AACjD,UAAM,aAAa,MAAM,YAAY,OAAO;AAC5C,UAAM,OAAO,MAAY;AACxB,YAAM,SAAS,WAAW,YAAY;AACtC,cAAQ;AAAA;AAAA,QAEP,MAAM,SAAS,WAAW,YAAY,IAAI,MAAM;AAAA,QAChD,OAAO,eAAe,UAAiC;AAAA,QACvD,OAAO;AAAA,MACR,CAAC;AAAA,IACF;AACA,UAAM,cAAc,WAAW,UAAU,IAAI;AAC7C,SAAK;AACL,cAAU,MAAM;AACf,kBAAY;AACZ,YAAM,QAAQ,OAAgC;AAAA,IAC/C;AAAA,EACD;AAEA,QAAM,QAA2B,CAAC;AAClC,MAAI,CAAC,eAAe,KAAK,GAAG;AAC3B,UAAM;AAAA,MACL,MAAM,UAAU,CAAC,SAAS;AACzB,kBAAU,QAAQ;AAClB,cAAM;AAAA,MACP,CAAC;AAAA,IACF;AAAA,EACD;AACA,MAAI,WAAW,YAAY,GAAG;AAC7B,UAAM;AAAA,MACL,aAAa,UAAU,CAAC,SAAS;AAChC,kBAAU,SAAS;AACnB,cAAM;AAAA,MACP,CAAC;AAAA,IACF;AAAA,EACD;AACA,QAAM;AAEN,SAAO,MAAM;AACZ,eAAW,QAAQ,MAAO,MAAK;AAC/B,cAAU;AACV,cAAU;AACV,gBAAY;AAAA,EACb;AACD;AAoBO,SAAS,iBACf,OACA,SACyB;AACzB,QAAM,EAAE,gBAAgB,IAAI,eAAe;AAC3C,QAAM,YAA6B;AAAA,IAClC,GAAG;AAAA,IACH,SACC,SAAS,YACR,CAAC,YAAmB;AAEpB,sBAAgB,OAAO;AAAA,IACxB;AAAA,EACF;AACA,aAAO;AAAA,IAAuB;AAAA,IAA6B,CAAC,QAC3D,YAAY,iBAAiB,OAAO,WAAW,CAAC,UAAU,IAAI,MAAM,IAAI,CAAC;AAAA,EAC1E;AACD;AASO,SAAS,sBACf,OACA,SAC0B;AAC1B,QAAM,EAAE,gBAAgB,IAAI,eAAe;AAC3C,QAAM,UAAyB,EAAE,MAAM,aAA6B,OAAO,MAAM,OAAO,MAAM;AAC9F,aAAO;AAAA,IAAwB;AAAA,IAAS,CAAC,QACxC,YAAY,iBAAiB,OAAO,SAAS,GAAG;AAAA,EACjD;AACD;AAMA,SAAS,gBAAgB,SAAsB;AAC9C,QAAM,OAAO;AACb,OAAK,SAAS,MAAM,mCAAmC,OAAO;AAC/D;AAGO,IAAM,WAAW;AAGjB,IAAM,gBAAgB;;;ACzL7B,sBAAyC;AACzC,IAAAC,iBAA0B;AAMnB,SAAS,eACf,YACA,SACkC;AAClC,QAAM,aAAa,EAAE,SAAS,QAAQ;AACtC,aAAW,UAAU;AAErB,QAAM,QAAQ,EAAE,SAAS,WAAW;AACpC,QAAM,UAAU;AAEhB,QAAM,iBAAa,0CAAiD;AAAA,IACnE,YAAY,IAAI,SAAS,MAAM,QAAQ,GAAG,IAAI;AAAA,IAC9C,gBAAgB,MAAM,WAAW;AAAA,EAClC,CAAC;AAED,QAAM,mBAAmB,oBAAI,IAA8B;AAC3D,QAAM,iBAAiB,oBAAI,IAAmC;AAE9D,QAAM,cAAc,WAAW,UAAU,MAAM;AAC9C,UAAM,WAAW,WAAW,YAAY;AACxC,eAAW,YAAY,kBAAkB;AACxC,eAAS,SAAS,SAAS;AAAA,IAC5B;AACA,eAAW,YAAY,gBAAgB;AACtC,eAAS,SAAS,KAAK;AAAA,IACxB;AAAA,EACD,CAAC;AAMD,MAAI;AACH,kCAAU,MAAM;AACf,kBAAY;AACZ,iBAAW,QAAQ;AAAA,IACpB,CAAC;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,SAAO;AAAA,IACN,QAAQ,IAAI,SAAgB,WAAW,OAAO,GAAG,IAAI;AAAA,IACrD,aAAa,IAAI,SAAgB,WAAW,YAAY,GAAG,IAAI;AAAA,IAC/D,kBAAkB,CAAC,OAAO;AACzB,uBAAiB,IAAI,EAAE;AACvB,SAAG,WAAW,YAAY,EAAE,SAAS;AACrC,aAAO,MAAM,iBAAiB,OAAO,EAAE;AAAA,IACxC;AAAA,IACA,gBAAgB,CAAC,OAAO;AACvB,qBAAe,IAAI,EAAE;AACrB,SAAG,WAAW,YAAY,EAAE,KAAK;AACjC,aAAO,MAAM,eAAe,OAAO,EAAE;AAAA,IACtC;AAAA,IACA,IAAI,UAAU;AACb,aAAO,WAAW,YAAY,EAAE;AAAA,IACjC;AAAA,IACA,IAAI,YAAY;AACf,aAAO,WAAW,YAAY,EAAE;AAAA,IACjC;AAAA,IACA,IAAI,QAAQ;AACX,aAAO,WAAW,YAAY,EAAE;AAAA,IACjC;AAAA,IACA,OAAO,MAAM,WAAW,MAAM;AAAA,EAC/B;AACD;AAGO,IAAM,cAAc;;;AC3E3B,kBAAgE;AAEhE,IAAAC,gBAAwC;AAMjC,SAAS,wBAAkD;AACjE,QAAM,EAAE,YAAY,qBAAqB,OAAO,IAAI,eAAe;AAEnE,aAAO,wBAAyB,iCAAqB,CAAC,QAAQ;AAC7D,UAAM,iBAAa,wCAA2B;AAAA,MAC7C;AAAA,MACA;AAAA,MACA,QAAQ,sBAAsB,OAAO;AAAA,IACtC,CAAC;AACD,QAAI,WAAW,YAAY,CAAC;AAC5B,UAAM,cAAc,WAAW,UAAU,MAAM;AAC9C,UAAI,WAAW,YAAY,CAAC;AAAA,IAC7B,CAAC;AACD,WAAO,MAAM;AACZ,kBAAY;AACZ,iBAAW,QAAQ;AAAA,IACpB;AAAA,EACD,CAAC;AACF;AAGO,IAAM,gBAAgB;;;AC1BtB,SAAS,SAAiD;AAChE,QAAM,EAAE,IAAI,IAAI,eAAe;AAC/B,MAAI,CAAC,KAAK;AACT,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAGO,IAAM,SAAS;;;ACXf,SAAS,cAAc,MAAkC;AAC/D,QAAM,EAAE,MAAM,IAAI,eAAe;AACjC,SAAO,MAAM,WAAW,IAAI;AAC7B;AAGO,IAAM,gBAAgB;;;ACT7B,IAAAC,gBAA+D;AAE/D,IAAAC,iBAA0B;AAC1B,IAAAD,gBAA6C;AAetC,SAAS,sBACf,gBACA,UACA,WACA,SAC8E;AAC9E,QAAM,EAAE,OAAO,WAAW,IAAI,eAAe;AAE7C,QAAM,iBAAa,wCAAyB;AAAA,IAC3C,YAAY,MAAM,WAAW,cAAc;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAY,oCAAqB,UAAU;AAAA,IAC3C,eAAe,SAAS;AAAA,IACxB,MAAM,SAAS;AAAA,EAChB,CAAC;AAED,gCAAU,MAAM;AACf,eAAW,QAAQ;AAAA,EACpB,CAAC;AAED,QAAM,kBAAc,wBAA4B,YAAY,UAAU,GAAG,CAAC,QAAQ;AACjF,UAAM,OAAO,MAAY;AACxB,UAAI,YAAY,UAAU,CAAC;AAAA,IAC5B;AACA,SAAK;AACL,WAAO,WAAW,UAAU,IAAI;AAAA,EACjC,CAAC;AAED,SAAO;AAAA,IACN,IAAI,MAAM;AACT,aAAO,WAAW;AAAA,IACnB;AAAA,IACA,IAAI,OAAO;AACV,aAAO,WAAW;AAAA,IACnB;AAAA,IACA,MAAM,MAAM,WAAW,KAAK;AAAA,IAC5B,MAAM,MAAM,WAAW,KAAK;AAAA,IAC5B,IAAI,QAAQ;AACX,iBAAO,mBAAI,WAAW,EAAE;AAAA,IACzB;AAAA,IACA,IAAI,QAAQ;AACX,iBAAO,mBAAI,WAAW,EAAE;AAAA,IACzB;AAAA,IACA,IAAI,UAAU;AACb,iBAAO,mBAAI,WAAW,EAAE;AAAA,IACzB;AAAA,IACA,IAAI,UAAU;AACb,iBAAO,mBAAI,WAAW,EAAE;AAAA,IACzB;AAAA,IACA,IAAI,UAAU;AACb,iBAAO,mBAAI,WAAW,EAAE;AAAA,IACzB;AAAA,IACA,WAAW,CAAC,QAAgB,SAAiB,WAAW,UAAU,QAAQ,IAAI;AAAA,IAC9E,aAAa,MAAM,WAAW,YAAY;AAAA,IAC1C,WAAW,YAAY;AAAA,EACxB;AACD;AAGO,IAAM,cAAc;AAE3B,SAAS,YAAY,YAA4E;AAChG,QAAM,WAAW,WAAW,YAAY;AACxC,SAAO;AAAA,IACN,KAAK,WAAW;AAAA,IAChB,MAAM,WAAW;AAAA,IACjB,MAAM,MAAM,WAAW,KAAK;AAAA,IAC5B,MAAM,MAAM,WAAW,KAAK;AAAA,IAC5B,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,IAChB,SAAS,SAAS;AAAA,IAClB,SAAS,SAAS;AAAA,IAClB,SAAS,CAAC,GAAG,SAAS,OAAO;AAAA,IAC7B,WAAW,CAAC,QAAQ,SAAS,WAAW,UAAU,QAAQ,IAAI;AAAA,IAC9D,aAAa,MAAM,WAAW,YAAY;AAAA,EAC3C;AACD;;;ACzFO,SAAS,cACf,MACa;AACb,QAAM,EAAE,WAAW,IAAI,eAAe;AACtC,MAAI,CAAC,cAAc,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;AAC/C,WAAO,MAAM;AAAA,IAAC;AAAA,EACf;AAEA,QAAM,YAAY,WAAW,oBAAoB;AACjD,YAAU,cAAc;AAAA,IACvB,MAAM;AAAA,MACL,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,IACd;AAAA,EACD,CAAC;AAED,SAAO,MAAM;AACZ,cAAU,cAAc,IAAI;AAAA,EAC7B;AACD;AAGO,IAAM,cAAc;;;AC9B3B,IAAAE,eAA+C;AAC/C,IAAAC,gBAAwC;AAMjC,SAAS,2BAAuD;AACtE,QAAM,EAAE,WAAW,IAAI,eAAe;AAEtC,aAAO,wBAA2B,CAAC,GAAG,CAAC,QAAQ;AAC9C,QAAI,CAAC,YAAY;AAChB,UAAI,CAAC,CAAC;AACN,aAAO,MAAM;AAAA,MAAC;AAAA,IACf;AAEA,UAAM,YAAY,WAAW,oBAAoB;AACjD,eAAO,6CAA+B,WAAW,GAAG;AAAA,EACrD,CAAC;AACF;AAGO,IAAM,mBAAmB;","names":["import_store","import_svelte","import_store","import_store","import_svelte","import_sync","import_store"]}
package/dist/index.d.cts CHANGED
@@ -1,12 +1,27 @@
1
1
  import { KoraAppLike as KoraAppLike$1, KoraContextValue as KoraContextValue$1, UseMutationOptions as UseMutationOptions$1, UseMutationResultBase, UseQueryOptions as UseQueryOptions$1 } from '@korajs/core/bindings';
2
- import { Store, QueryStoreCache, CollectionRecord, QueryBuilder, CollectionAccessor } from '@korajs/store';
2
+ import { Store, QueryStoreCache, QueryBuilder, CollectionRecord, CollectionAccessor } from '@korajs/store';
3
3
  import { SyncEngine, CursorInfo, SyncStatusInfo, AwarenessUser, AwarenessState } from '@korajs/sync';
4
- import * as Y from 'yjs';
5
4
  import { Readable } from 'svelte/store';
5
+ import * as Y from 'yjs';
6
6
 
7
7
  type KoraAppLike = KoraAppLike$1<Store, SyncEngine, QueryStoreCache>;
8
8
  type KoraContextValue = KoraContextValue$1<Store, SyncEngine, QueryStoreCache>;
9
- type UseQueryOptions = UseQueryOptions$1;
9
+ /** Options for `createQueryStore` and `createQueryStateStore`. */
10
+ interface UseQueryOptions extends Omit<UseQueryOptions$1, 'enabled'> {
11
+ /** When false, the query subscription is disabled. A value or a readable store. Defaults to true. */
12
+ enabled?: boolean | Readable<boolean>;
13
+ /** Called when the query fails (STORE-12). `createQueryStore` logs to `console.error` without it. */
14
+ onError?: (error: Error) => void;
15
+ }
16
+ /** Value of `createQueryStateStore`. */
17
+ interface QueryState<T> {
18
+ /** The current rows (the last good rows while `error` is set). */
19
+ data: readonly T[];
20
+ /** The query's failure, or null. Cleared when results flow again. */
21
+ error: Error | null;
22
+ /** False until the first result for the current query arrived. */
23
+ ready: boolean;
24
+ }
10
25
  type UseMutationOptions<TData, TArgs extends unknown[], TContext = void> = UseMutationOptions$1<TData, TArgs, TContext>;
11
26
  interface UseMutationResult<TData, TArgs extends unknown[]> extends UseMutationResultBase<TData, TArgs> {
12
27
  subscribeLoading: (fn: (value: boolean) => void) => () => void;
@@ -44,15 +59,39 @@ declare function getKoraApp(): KoraAppLike;
44
59
  */
45
60
  declare function initKoraProvider(app: KoraAppLike): Promise<KoraContextValue>;
46
61
 
62
+ /** A query input: a builder, or a readable store of one (null disables). */
63
+ type QueryInput<T> = QueryBuilder<T> | Readable<QueryBuilder<T> | null | undefined>;
64
+ /**
65
+ * Create a Svelte readable store of a Kora query's rows.
66
+ *
67
+ * The query and `enabled` may be plain values or readable stores: pass a store (for
68
+ * example a `derived` of your filter) and the rows follow it, re-subscribing when the
69
+ * query's descriptor changes. A failed query is reported through `options.onError`,
70
+ * or `console.error` without one; use {@link createQueryStateStore} to render it.
71
+ *
72
+ * @param query - A query builder, or a readable store of one (null disables)
73
+ * @param options - `enabled` (value or readable store; default true) and `onError`
74
+ * @returns A readable store of the current rows
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const filter = writable(false)
79
+ * const todos = createQueryStore(derived(filter, (done) => app.todos.where({ completed: done })))
80
+ * ```
81
+ */
82
+ declare function createQueryStore<T = CollectionRecord>(query: QueryInput<T>, options?: UseQueryOptions): Readable<readonly T[]>;
47
83
  /**
48
- * Create a Svelte readable store for a static Kora query.
84
+ * Like {@link createQueryStore}, but the store holds `{ data, error, ready }`.
49
85
  *
50
- * For reactive filter changes, use {@link KoraQuery} which re-subscribes when the
51
- * query descriptor changes.
86
+ * @param query - A query builder, or a readable store of one
87
+ * @param options - `enabled` and `onError`
88
+ * @returns A readable store of the query state
52
89
  */
53
- declare function createQueryStore<T = CollectionRecord>(query: QueryBuilder<T>, options?: UseQueryOptions): Readable<readonly T[]>;
90
+ declare function createQueryStateStore<T = CollectionRecord>(query: QueryInput<T>, options?: UseQueryOptions): Readable<QueryState<T>>;
54
91
  /** Alias for {@link createQueryStore}. */
55
92
  declare const useQuery: typeof createQueryStore;
93
+ /** Alias for {@link createQueryStateStore}. */
94
+ declare const useQueryState: typeof createQueryStateStore;
56
95
 
57
96
  /**
58
97
  * Create a mutation controller with optimistic update hooks.
@@ -113,4 +152,4 @@ declare function createCollaboratorsStore(): Readable<AwarenessState[]>;
113
152
  /** Alias for {@link createCollaboratorsStore}. */
114
153
  declare const useCollaborators: typeof createCollaboratorsStore;
115
154
 
116
- export { type KoraAppHandle, type KoraAppLike, type KoraContextValue, type UseMutationOptions, type UseMutationResult, type UseQueryOptions, type UseRichTextOptions, type UseRichTextResult, applyPresence, createCollaboratorsStore, createMutation, createQueryStore, createRichTextBinding, createSyncStatusStore, getApp, getCollection, getKoraApp, getKoraContext, initKoraProvider, setKoraAppContext, setKoraContext, useApp, useCollaborators, useCollection, useMutation, usePresence, useQuery, useRichText, useSyncStatus };
155
+ export { type KoraAppHandle, type KoraAppLike, type KoraContextValue, type QueryInput, type QueryState, type UseMutationOptions, type UseMutationResult, type UseQueryOptions, type UseRichTextOptions, type UseRichTextResult, applyPresence, createCollaboratorsStore, createMutation, createQueryStateStore, createQueryStore, createRichTextBinding, createSyncStatusStore, getApp, getCollection, getKoraApp, getKoraContext, initKoraProvider, setKoraAppContext, setKoraContext, useApp, useCollaborators, useCollection, useMutation, usePresence, useQuery, useQueryState, useRichText, useSyncStatus };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,27 @@
1
1
  import { KoraAppLike as KoraAppLike$1, KoraContextValue as KoraContextValue$1, UseMutationOptions as UseMutationOptions$1, UseMutationResultBase, UseQueryOptions as UseQueryOptions$1 } from '@korajs/core/bindings';
2
- import { Store, QueryStoreCache, CollectionRecord, QueryBuilder, CollectionAccessor } from '@korajs/store';
2
+ import { Store, QueryStoreCache, QueryBuilder, CollectionRecord, CollectionAccessor } from '@korajs/store';
3
3
  import { SyncEngine, CursorInfo, SyncStatusInfo, AwarenessUser, AwarenessState } from '@korajs/sync';
4
- import * as Y from 'yjs';
5
4
  import { Readable } from 'svelte/store';
5
+ import * as Y from 'yjs';
6
6
 
7
7
  type KoraAppLike = KoraAppLike$1<Store, SyncEngine, QueryStoreCache>;
8
8
  type KoraContextValue = KoraContextValue$1<Store, SyncEngine, QueryStoreCache>;
9
- type UseQueryOptions = UseQueryOptions$1;
9
+ /** Options for `createQueryStore` and `createQueryStateStore`. */
10
+ interface UseQueryOptions extends Omit<UseQueryOptions$1, 'enabled'> {
11
+ /** When false, the query subscription is disabled. A value or a readable store. Defaults to true. */
12
+ enabled?: boolean | Readable<boolean>;
13
+ /** Called when the query fails (STORE-12). `createQueryStore` logs to `console.error` without it. */
14
+ onError?: (error: Error) => void;
15
+ }
16
+ /** Value of `createQueryStateStore`. */
17
+ interface QueryState<T> {
18
+ /** The current rows (the last good rows while `error` is set). */
19
+ data: readonly T[];
20
+ /** The query's failure, or null. Cleared when results flow again. */
21
+ error: Error | null;
22
+ /** False until the first result for the current query arrived. */
23
+ ready: boolean;
24
+ }
10
25
  type UseMutationOptions<TData, TArgs extends unknown[], TContext = void> = UseMutationOptions$1<TData, TArgs, TContext>;
11
26
  interface UseMutationResult<TData, TArgs extends unknown[]> extends UseMutationResultBase<TData, TArgs> {
12
27
  subscribeLoading: (fn: (value: boolean) => void) => () => void;
@@ -44,15 +59,39 @@ declare function getKoraApp(): KoraAppLike;
44
59
  */
45
60
  declare function initKoraProvider(app: KoraAppLike): Promise<KoraContextValue>;
46
61
 
62
+ /** A query input: a builder, or a readable store of one (null disables). */
63
+ type QueryInput<T> = QueryBuilder<T> | Readable<QueryBuilder<T> | null | undefined>;
64
+ /**
65
+ * Create a Svelte readable store of a Kora query's rows.
66
+ *
67
+ * The query and `enabled` may be plain values or readable stores: pass a store (for
68
+ * example a `derived` of your filter) and the rows follow it, re-subscribing when the
69
+ * query's descriptor changes. A failed query is reported through `options.onError`,
70
+ * or `console.error` without one; use {@link createQueryStateStore} to render it.
71
+ *
72
+ * @param query - A query builder, or a readable store of one (null disables)
73
+ * @param options - `enabled` (value or readable store; default true) and `onError`
74
+ * @returns A readable store of the current rows
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const filter = writable(false)
79
+ * const todos = createQueryStore(derived(filter, (done) => app.todos.where({ completed: done })))
80
+ * ```
81
+ */
82
+ declare function createQueryStore<T = CollectionRecord>(query: QueryInput<T>, options?: UseQueryOptions): Readable<readonly T[]>;
47
83
  /**
48
- * Create a Svelte readable store for a static Kora query.
84
+ * Like {@link createQueryStore}, but the store holds `{ data, error, ready }`.
49
85
  *
50
- * For reactive filter changes, use {@link KoraQuery} which re-subscribes when the
51
- * query descriptor changes.
86
+ * @param query - A query builder, or a readable store of one
87
+ * @param options - `enabled` and `onError`
88
+ * @returns A readable store of the query state
52
89
  */
53
- declare function createQueryStore<T = CollectionRecord>(query: QueryBuilder<T>, options?: UseQueryOptions): Readable<readonly T[]>;
90
+ declare function createQueryStateStore<T = CollectionRecord>(query: QueryInput<T>, options?: UseQueryOptions): Readable<QueryState<T>>;
54
91
  /** Alias for {@link createQueryStore}. */
55
92
  declare const useQuery: typeof createQueryStore;
93
+ /** Alias for {@link createQueryStateStore}. */
94
+ declare const useQueryState: typeof createQueryStateStore;
56
95
 
57
96
  /**
58
97
  * Create a mutation controller with optimistic update hooks.
@@ -113,4 +152,4 @@ declare function createCollaboratorsStore(): Readable<AwarenessState[]>;
113
152
  /** Alias for {@link createCollaboratorsStore}. */
114
153
  declare const useCollaborators: typeof createCollaboratorsStore;
115
154
 
116
- export { type KoraAppHandle, type KoraAppLike, type KoraContextValue, type UseMutationOptions, type UseMutationResult, type UseQueryOptions, type UseRichTextOptions, type UseRichTextResult, applyPresence, createCollaboratorsStore, createMutation, createQueryStore, createRichTextBinding, createSyncStatusStore, getApp, getCollection, getKoraApp, getKoraContext, initKoraProvider, setKoraAppContext, setKoraContext, useApp, useCollaborators, useCollection, useMutation, usePresence, useQuery, useRichText, useSyncStatus };
155
+ export { type KoraAppHandle, type KoraAppLike, type KoraContextValue, type QueryInput, type QueryState, type UseMutationOptions, type UseMutationResult, type UseQueryOptions, type UseRichTextOptions, type UseRichTextResult, applyPresence, createCollaboratorsStore, createMutation, createQueryStateStore, createQueryStore, createRichTextBinding, createSyncStatusStore, getApp, getCollection, getKoraApp, getKoraContext, initKoraProvider, setKoraAppContext, setKoraContext, useApp, useCollaborators, useCollection, useMutation, usePresence, useQuery, useQueryState, useRichText, useSyncStatus };