@korajs/react 0.4.0 → 0.5.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.cjs CHANGED
@@ -91,7 +91,9 @@ function KoraProvider({
91
91
  const value = {
92
92
  store: resolvedStore,
93
93
  syncEngine: resolvedSync,
94
- app: app ?? null
94
+ app: app ?? null,
95
+ events: app?.events ?? null,
96
+ subscribeSyncStatus: app?.sync?.subscribeStatus ?? null
95
97
  };
96
98
  return (0, import_react.createElement)(KoraContext.Provider, { value }, children);
97
99
  }
@@ -191,6 +193,18 @@ var QueryStore = class {
191
193
  };
192
194
 
193
195
  // src/hooks/use-query.ts
196
+ var APP_NOT_READY_CODE = "APP_NOT_READY";
197
+ function assertQueryReady(query) {
198
+ const descriptor = query.getDescriptor();
199
+ if (descriptor.collection === "__pending__") {
200
+ const err = new Error(
201
+ "Cannot use useQuery() before app.ready. Await app.ready or wrap your UI in <KoraProvider app={app}>."
202
+ );
203
+ err.name = "AppNotReadyError";
204
+ Object.assign(err, { code: APP_NOT_READY_CODE });
205
+ throw err;
206
+ }
207
+ }
194
208
  var EMPTY_ARRAY2 = Object.freeze([]);
195
209
  var noopSubscribe = (_onStoreChange) => {
196
210
  return () => {
@@ -198,6 +212,9 @@ var noopSubscribe = (_onStoreChange) => {
198
212
  };
199
213
  function useQuery(query, options) {
200
214
  const enabled = options?.enabled !== false;
215
+ if (enabled) {
216
+ assertQueryReady(query);
217
+ }
201
218
  const descriptorKey = JSON.stringify(query.getDescriptor());
202
219
  const queryStoreRef = (0, import_react2.useRef)(null);
203
220
  const prevKeyRef = (0, import_react2.useRef)(null);
@@ -230,7 +247,7 @@ function useQuery(query, options) {
230
247
 
231
248
  // src/hooks/use-mutation.ts
232
249
  var import_react3 = require("react");
233
- function useMutation(mutationFn) {
250
+ function useMutation(mutationFn, options) {
234
251
  const [state, setState] = (0, import_react3.useState)({
235
252
  isLoading: false,
236
253
  error: null
@@ -244,21 +261,35 @@ function useMutation(mutationFn) {
244
261
  }, []);
245
262
  const fnRef = (0, import_react3.useRef)(mutationFn);
246
263
  fnRef.current = mutationFn;
264
+ const optionsRef = (0, import_react3.useRef)(options);
265
+ optionsRef.current = options;
247
266
  const mutateAsync = (0, import_react3.useCallback)(async (...args) => {
267
+ const opts = optionsRef.current;
268
+ let context;
248
269
  if (mountedRef.current) {
249
270
  setState({ isLoading: true, error: null });
250
271
  }
251
272
  try {
273
+ if (opts?.onMutate) {
274
+ context = await opts.onMutate(...args);
275
+ }
252
276
  const result = await fnRef.current(...args);
253
277
  if (mountedRef.current) {
254
278
  setState({ isLoading: false, error: null });
255
279
  }
280
+ opts?.onSuccess?.(result, ...args);
281
+ opts?.onSettled?.(result, null, ...args);
256
282
  return result;
257
283
  } catch (err) {
258
284
  const error = err instanceof Error ? err : new Error(String(err));
285
+ if (context !== void 0 && opts?.onRollback) {
286
+ await opts.onRollback(context, ...args);
287
+ }
259
288
  if (mountedRef.current) {
260
289
  setState({ isLoading: false, error });
261
290
  }
291
+ opts?.onError?.(error, ...args);
292
+ opts?.onSettled?.(void 0, error, ...args);
262
293
  throw error;
263
294
  }
264
295
  }, []);
@@ -285,7 +316,6 @@ function useMutation(mutationFn) {
285
316
 
286
317
  // src/hooks/use-sync-status.ts
287
318
  var import_react4 = require("react");
288
- var POLL_INTERVAL_MS = 500;
289
319
  var OFFLINE_STATUS = Object.freeze({
290
320
  status: "offline",
291
321
  pendingOperations: 0,
@@ -294,15 +324,36 @@ var OFFLINE_STATUS = Object.freeze({
294
324
  lastSuccessfulPull: null,
295
325
  conflicts: 0
296
326
  });
327
+ var SYNC_STATUS_EVENT_TYPES = [
328
+ "sync:connected",
329
+ "sync:disconnected",
330
+ "sync:schema-mismatch",
331
+ "sync:auth-failed",
332
+ "sync:sent",
333
+ "sync:received",
334
+ "sync:acknowledged",
335
+ "sync:apply-failed",
336
+ "sync:diagnostics",
337
+ "sync:initial-sync-progress"
338
+ ];
297
339
  function useSyncStatus() {
298
- const { syncEngine } = useKoraContext();
340
+ const { syncEngine, subscribeSyncStatus, events } = useKoraContext();
299
341
  const snapshotRef = (0, import_react4.useRef)(OFFLINE_STATUS);
300
342
  const serializedRef = (0, import_react4.useRef)(JSON.stringify(OFFLINE_STATUS));
301
343
  const subscribe = (0, import_react4.useCallback)(
302
344
  (onStoreChange) => {
303
- if (!syncEngine) return () => {
304
- };
305
- const intervalId = setInterval(() => {
345
+ if (subscribeSyncStatus) {
346
+ return subscribeSyncStatus((status) => {
347
+ snapshotRef.current = status;
348
+ serializedRef.current = JSON.stringify(status);
349
+ onStoreChange();
350
+ });
351
+ }
352
+ if (!syncEngine) {
353
+ return () => {
354
+ };
355
+ }
356
+ const refresh = () => {
306
357
  const newStatus = syncEngine.getStatus();
307
358
  const newSerialized = JSON.stringify(newStatus);
308
359
  if (newSerialized !== serializedRef.current) {
@@ -310,29 +361,28 @@ function useSyncStatus() {
310
361
  serializedRef.current = newSerialized;
311
362
  onStoreChange();
312
363
  }
313
- }, POLL_INTERVAL_MS);
314
- const initialStatus = syncEngine.getStatus();
315
- const initialSerialized = JSON.stringify(initialStatus);
316
- if (initialSerialized !== serializedRef.current) {
317
- snapshotRef.current = initialStatus;
318
- serializedRef.current = initialSerialized;
319
- onStoreChange();
364
+ };
365
+ if (events) {
366
+ const unsubs = SYNC_STATUS_EVENT_TYPES.map((type) => events.on(type, refresh));
367
+ refresh();
368
+ return () => {
369
+ for (const unsub of unsubs) {
370
+ unsub();
371
+ }
372
+ };
320
373
  }
374
+ refresh();
321
375
  return () => {
322
- clearInterval(intervalId);
323
376
  };
324
377
  },
325
- [syncEngine]
378
+ [syncEngine, subscribeSyncStatus, events]
326
379
  );
327
380
  const getSnapshot = (0, import_react4.useCallback)(() => {
328
- return snapshotRef.current;
329
- }, []);
330
- (0, import_react4.useEffect)(() => {
331
- if (!syncEngine) {
332
- snapshotRef.current = OFFLINE_STATUS;
333
- serializedRef.current = JSON.stringify(OFFLINE_STATUS);
381
+ if (subscribeSyncStatus) {
382
+ return snapshotRef.current;
334
383
  }
335
- }, [syncEngine]);
384
+ return syncEngine ? syncEngine.getStatus() : OFFLINE_STATUS;
385
+ }, [syncEngine, subscribeSyncStatus]);
336
386
  return (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot);
337
387
  }
338
388
 
@@ -346,12 +396,16 @@ function useCollection(name) {
346
396
  }
347
397
 
348
398
  // src/hooks/use-rich-text.ts
399
+ var import_store = require("@korajs/store");
349
400
  var import_react6 = require("react");
350
401
  var Y = __toESM(require("yjs"), 1);
351
402
  var LOAD_ORIGIN = "kora-load";
403
+ var REMOTE_ORIGIN = "kora-remote";
404
+ var DOC_CHANNEL_ORIGIN = "kora-doc-channel";
352
405
  var TEXT_KEY = "content";
353
406
  var COMPACT_AFTER_DELTAS = 20;
354
- function useRichText(collectionName, recordId, fieldName) {
407
+ var PERSIST_DEBOUNCE_MS = 400;
408
+ function useRichText(collectionName, recordId, fieldName, options) {
355
409
  const { store, syncEngine } = useKoraContext();
356
410
  const collection = (0, import_react6.useMemo)(
357
411
  () => store.collection(collectionName),
@@ -365,6 +419,12 @@ function useRichText(collectionName, recordId, fieldName) {
365
419
  const [cursors, setCursors] = (0, import_react6.useState)([]);
366
420
  const baseUpdateRef = (0, import_react6.useRef)(null);
367
421
  const pendingDeltasRef = (0, import_react6.useRef)([]);
422
+ const docChannelActiveRef = (0, import_react6.useRef)(false);
423
+ const persistTimerRef = (0, import_react6.useRef)(null);
424
+ const userRef = (0, import_react6.useRef)(options?.user);
425
+ (0, import_react6.useEffect)(() => {
426
+ userRef.current = options?.user;
427
+ }, [options?.user]);
368
428
  const text = (0, import_react6.useMemo)(() => doc.getText(TEXT_KEY), [doc]);
369
429
  const undoManager = (0, import_react6.useMemo)(() => new Y.UndoManager(text), [text]);
370
430
  const syncHistoryState = (0, import_react6.useCallback)(() => {
@@ -379,6 +439,72 @@ function useRichText(collectionName, recordId, fieldName) {
379
439
  undoManager.redo();
380
440
  syncHistoryState();
381
441
  }, [syncHistoryState, undoManager]);
442
+ const resolveAwarenessUser = (0, import_react6.useCallback)(() => {
443
+ if (userRef.current) {
444
+ return userRef.current;
445
+ }
446
+ if (syncEngine) {
447
+ const existing = syncEngine.getAwarenessManager().getLocalState()?.user;
448
+ if (existing) {
449
+ return existing;
450
+ }
451
+ }
452
+ return {
453
+ name: "Anonymous",
454
+ color: "#6366f1"
455
+ };
456
+ }, [syncEngine]);
457
+ const setCursor = (0, import_react6.useCallback)(
458
+ (anchor, head) => {
459
+ if (!syncEngine) {
460
+ return;
461
+ }
462
+ const awareness = syncEngine.getAwarenessManager();
463
+ const state = {
464
+ user: resolveAwarenessUser(),
465
+ cursor: {
466
+ collection: collectionName,
467
+ recordId,
468
+ field: fieldName,
469
+ anchor,
470
+ head
471
+ }
472
+ };
473
+ awareness.setLocalState(state);
474
+ },
475
+ [collectionName, fieldName, recordId, resolveAwarenessUser, syncEngine]
476
+ );
477
+ const clearCursor = (0, import_react6.useCallback)(() => {
478
+ if (!syncEngine) {
479
+ return;
480
+ }
481
+ const awareness = syncEngine.getAwarenessManager();
482
+ const current = awareness.getLocalState();
483
+ if (!current?.cursor) {
484
+ return;
485
+ }
486
+ if (current.cursor.collection !== collectionName || current.cursor.recordId !== recordId || current.cursor.field !== fieldName) {
487
+ return;
488
+ }
489
+ awareness.setLocalState({ user: current.user });
490
+ }, [collectionName, fieldName, recordId, syncEngine]);
491
+ const applyRemoteSnapshot = (0, import_react6.useCallback)(
492
+ (value) => {
493
+ const encoded = encodeRichtextInput(value);
494
+ if (!encoded) {
495
+ return;
496
+ }
497
+ const currentSnapshot = Y.encodeStateAsUpdate(doc);
498
+ if (updatesEqual(currentSnapshot, encoded)) {
499
+ return;
500
+ }
501
+ Y.applyUpdate(doc, encoded, REMOTE_ORIGIN);
502
+ baseUpdateRef.current = encoded;
503
+ pendingDeltasRef.current = [];
504
+ syncHistoryState();
505
+ },
506
+ [doc, syncHistoryState]
507
+ );
382
508
  (0, import_react6.useEffect)(() => {
383
509
  let disposed = false;
384
510
  const initialize = async () => {
@@ -397,18 +523,15 @@ function useRichText(collectionName, recordId, fieldName) {
397
523
  if (encoded) {
398
524
  Y.applyUpdate(doc, encoded, LOAD_ORIGIN);
399
525
  }
526
+ const channel = syncEngine?.getRichtextDocChannel?.();
527
+ docChannelActiveRef.current = channel?.shouldUseChannel(encoded?.length ?? 0, options?.useDocChannel) ?? false;
400
528
  setReady(true);
401
529
  } catch (cause) {
402
530
  if (disposed) return;
403
531
  setError(cause instanceof Error ? cause : new Error(String(cause)));
404
532
  }
405
533
  };
406
- const persist = async (_update, origin) => {
407
- syncHistoryState();
408
- if (origin === LOAD_ORIGIN) {
409
- return;
410
- }
411
- pendingDeltasRef.current.push(_update);
534
+ const flushPersist = async () => {
412
535
  const snapshot = composeRichtextSnapshot(baseUpdateRef.current, pendingDeltasRef.current);
413
536
  if (pendingDeltasRef.current.length >= COMPACT_AFTER_DELTAS) {
414
537
  baseUpdateRef.current = snapshot;
@@ -424,17 +547,77 @@ function useRichText(collectionName, recordId, fieldName) {
424
547
  }
425
548
  }
426
549
  };
550
+ const schedulePersist = () => {
551
+ if (persistTimerRef.current) {
552
+ clearTimeout(persistTimerRef.current);
553
+ }
554
+ persistTimerRef.current = setTimeout(() => {
555
+ persistTimerRef.current = null;
556
+ void flushPersist();
557
+ }, PERSIST_DEBOUNCE_MS);
558
+ };
559
+ const persist = (_update, origin) => {
560
+ syncHistoryState();
561
+ if (origin === LOAD_ORIGIN || origin === REMOTE_ORIGIN || origin === DOC_CHANNEL_ORIGIN) {
562
+ return;
563
+ }
564
+ pendingDeltasRef.current.push(_update);
565
+ if (docChannelActiveRef.current && syncEngine) {
566
+ syncEngine.getRichtextDocChannel().send(collectionName, recordId, fieldName, _update);
567
+ schedulePersist();
568
+ return;
569
+ }
570
+ void flushPersist();
571
+ };
427
572
  doc.on("update", persist);
428
573
  void initialize();
429
574
  syncHistoryState();
430
575
  return () => {
431
576
  disposed = true;
577
+ if (persistTimerRef.current) {
578
+ clearTimeout(persistTimerRef.current);
579
+ persistTimerRef.current = null;
580
+ }
432
581
  doc.off("update", persist);
433
582
  undoManager.destroy();
434
583
  baseUpdateRef.current = null;
435
584
  pendingDeltasRef.current = [];
585
+ docChannelActiveRef.current = false;
436
586
  };
437
- }, [collection, doc, fieldName, recordId, syncHistoryState, undoManager]);
587
+ }, [
588
+ collection,
589
+ collectionName,
590
+ doc,
591
+ fieldName,
592
+ options?.useDocChannel,
593
+ recordId,
594
+ syncEngine,
595
+ syncHistoryState,
596
+ undoManager
597
+ ]);
598
+ (0, import_react6.useEffect)(() => {
599
+ if (!ready || !syncEngine || !docChannelActiveRef.current) {
600
+ return;
601
+ }
602
+ const channel = syncEngine.getRichtextDocChannel();
603
+ return channel.subscribe(collectionName, recordId, fieldName, (update) => {
604
+ Y.applyUpdate(doc, update, DOC_CHANNEL_ORIGIN);
605
+ syncHistoryState();
606
+ });
607
+ }, [collectionName, doc, fieldName, ready, recordId, syncEngine, syncHistoryState]);
608
+ (0, import_react6.useEffect)(() => {
609
+ if (!ready) {
610
+ return;
611
+ }
612
+ const unsubscribe = store.collection(collectionName).where({ id: recordId }).subscribe((results) => {
613
+ const record = results[0];
614
+ if (!record) {
615
+ return;
616
+ }
617
+ applyRemoteSnapshot(record[fieldName]);
618
+ });
619
+ return unsubscribe;
620
+ }, [applyRemoteSnapshot, collectionName, fieldName, ready, recordId, store]);
438
621
  (0, import_react6.useEffect)(() => {
439
622
  if (!syncEngine) return;
440
623
  const awareness = syncEngine.getAwarenessManager();
@@ -462,42 +645,48 @@ function useRichText(collectionName, recordId, fieldName) {
462
645
  updateCursors();
463
646
  });
464
647
  updateCursors();
465
- return unsubscribe;
466
- }, [syncEngine, collectionName, recordId, fieldName]);
467
- return { doc, text, undo, redo, canUndo, canRedo, ready, error, cursors };
648
+ return () => {
649
+ unsubscribe();
650
+ clearCursor();
651
+ };
652
+ }, [clearCursor, collectionName, fieldName, recordId, syncEngine]);
653
+ return { doc, text, undo, redo, canUndo, canRedo, ready, error, cursors, setCursor, clearCursor };
468
654
  }
469
655
  function encodeRichtextInput(value) {
470
656
  if (value === null || value === void 0) {
471
657
  return null;
472
658
  }
473
- if (typeof value === "string") {
474
- const doc = new Y.Doc();
475
- doc.getText(TEXT_KEY).insert(0, value);
476
- return Y.encodeStateAsUpdate(doc);
477
- }
478
- if (value instanceof Uint8Array) {
479
- return value;
480
- }
481
- if (value instanceof ArrayBuffer) {
482
- return new Uint8Array(value);
483
- }
484
- if (typeof globalThis !== "undefined" && "Buffer" in globalThis) {
485
- const BufferCtor = globalThis.Buffer;
486
- if (BufferCtor.isBuffer(value)) {
487
- return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
659
+ try {
660
+ return (0, import_store.encodeRichtext)(value);
661
+ } catch {
662
+ if (typeof value === "string") {
663
+ const fallbackDoc = new Y.Doc();
664
+ fallbackDoc.getText(TEXT_KEY).insert(0, value);
665
+ return Y.encodeStateAsUpdate(fallbackDoc);
488
666
  }
667
+ throw new Error("Richtext record value must be a string, Uint8Array, ArrayBuffer, or null.");
489
668
  }
490
- throw new Error("Richtext record value must be a string, Uint8Array, ArrayBuffer, or null.");
491
669
  }
492
670
  function composeRichtextSnapshot(base, deltas) {
493
- const doc = new Y.Doc();
671
+ const mergedDoc = new Y.Doc();
494
672
  if (base) {
495
- Y.applyUpdate(doc, base);
673
+ Y.applyUpdate(mergedDoc, base);
496
674
  }
497
675
  for (const delta of deltas) {
498
- Y.applyUpdate(doc, delta);
676
+ Y.applyUpdate(mergedDoc, delta);
677
+ }
678
+ return Y.encodeStateAsUpdate(mergedDoc);
679
+ }
680
+ function updatesEqual(left, right) {
681
+ if (left.length !== right.length) {
682
+ return false;
683
+ }
684
+ for (let index = 0; index < left.length; index++) {
685
+ if (left[index] !== right[index]) {
686
+ return false;
687
+ }
499
688
  }
500
- return Y.encodeStateAsUpdate(doc);
689
+ return true;
501
690
  }
502
691
  // Annotate the CommonJS export names for ESM import in node:
503
692
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/context/kora-context.ts","../src/hooks/use-app.ts","../src/hooks/use-query.ts","../src/query-store/query-store.ts","../src/hooks/use-mutation.ts","../src/hooks/use-sync-status.ts","../src/hooks/use-collection.ts","../src/hooks/use-rich-text.ts"],"sourcesContent":["// @korajs/react — public API\n// Every export here is a public API commitment. Be explicit.\n\n// === Types ===\nexport type {\n\tKoraAppLike,\n\tKoraContextValue,\n\tKoraProviderProps,\n\tUseQueryOptions,\n\tUseMutationResult,\n\tUseRichTextResult,\n} from './types'\n\n// === Context ===\nexport { KoraProvider } from './context/kora-context'\n\n// === Hooks ===\nexport { useApp } from './hooks/use-app'\nexport { useQuery } from './hooks/use-query'\nexport { useMutation } from './hooks/use-mutation'\nexport { useSyncStatus } from './hooks/use-sync-status'\nexport { useCollection } from './hooks/use-collection'\nexport { useRichText } from './hooks/use-rich-text'\n","import type { Store } from '@korajs/store'\nimport type { SyncEngine } from '@korajs/sync'\nimport { createContext, createElement, useContext, useEffect, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport type { KoraContextValue, KoraProviderProps } from '../types'\n\nconst KoraContext = createContext<KoraContextValue | null>(null)\n\n/**\n * Provides Kora store and optional sync engine to all child components.\n * Must wrap any component that uses Kora hooks (useQuery, useMutation, etc.).\n *\n * Accepts either an `app` prop (recommended) or explicit `store` + `syncEngine` props.\n *\n * When using the `app` prop, KoraProvider waits for `app.ready` before rendering\n * children. A `fallback` prop can be provided to show content while initializing.\n *\n * @example\n * ```typescript\n * // Recommended: pass the app object directly\n * const app = createApp({ schema })\n * <KoraProvider app={app}><App /></KoraProvider>\n *\n * // Advanced: pass store and syncEngine explicitly\n * <KoraProvider store={store} syncEngine={syncEngine}><App /></KoraProvider>\n * ```\n */\nfunction KoraProvider({\n\tapp,\n\tstore,\n\tsyncEngine,\n\tfallback,\n\tchildren,\n}: KoraProviderProps): ReactNode {\n\tconst [resolvedStore, setResolvedStore] = useState<Store | null>(store ?? null)\n\tconst [resolvedSync, setResolvedSync] = useState<SyncEngine | null>(syncEngine ?? null)\n\t// If no app prop, we're using the store prop and are ready immediately\n\tconst [ready, setReady] = useState(!app)\n\tconst [initError, setInitError] = useState<Error | null>(null)\n\n\tuseEffect(() => {\n\t\tif (!app) return\n\t\tlet cancelled = false\n\t\tapp.ready\n\t\t\t.then(() => {\n\t\t\t\tif (cancelled) return\n\t\t\t\tsetResolvedStore(app.getStore())\n\t\t\t\tsetResolvedSync(app.getSyncEngine())\n\t\t\t\tsetReady(true)\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (cancelled) return\n\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error))\n\t\t\t\tconsole.error('[Kora] Initialization failed:', err)\n\t\t\t\tsetInitError(err)\n\t\t\t})\n\t\treturn () => {\n\t\t\tcancelled = true\n\t\t}\n\t}, [app])\n\n\tif (initError) {\n\t\treturn createElement(\n\t\t\t'div',\n\t\t\t{ style: { color: 'red', padding: '1rem', fontFamily: 'monospace' } },\n\t\t\tcreateElement('strong', null, 'Kora initialization error: '),\n\t\t\tinitError.message,\n\t\t)\n\t}\n\n\tif (!ready) {\n\t\treturn (fallback ?? null) as ReactNode\n\t}\n\n\tif (!resolvedStore) {\n\t\tthrow new Error(\n\t\t\t'KoraProvider requires either an \"app\" or \"store\" prop. ' +\n\t\t\t\t'Pass a KoraApp from createApp() or a Store instance.',\n\t\t)\n\t}\n\n\tconst value: KoraContextValue = {\n\t\tstore: resolvedStore,\n\t\tsyncEngine: resolvedSync,\n\t\tapp: app ?? null,\n\t}\n\treturn createElement(KoraContext.Provider, { value }, children)\n}\n\n/**\n * Internal hook to access the Kora context.\n * Throws if used outside of a KoraProvider.\n */\nfunction useKoraContext(): KoraContextValue {\n\tconst context = useContext(KoraContext)\n\tif (context === null) {\n\t\tthrow new Error(\n\t\t\t'useKoraContext must be used within a <KoraProvider>. ' +\n\t\t\t\t'Wrap your component tree with <KoraProvider store={store}>.',\n\t\t)\n\t}\n\treturn context\n}\n\nexport { KoraProvider, useKoraContext }\n","import { useKoraContext } from '../context/kora-context'\nimport type { KoraAppLike } from '../types'\n\n/**\n * React hook that returns the Kora app instance from context.\n *\n * Use the generic parameter to cast to your typed app for full type inference:\n *\n * ```typescript\n * // In your app setup:\n * export const app = createApp({ schema: mySchema })\n * export type App = typeof app\n *\n * // In components:\n * const app = useApp<App>()\n * app.todos.insert({ title: 'Hello' }) // fully typed\n * const todos = useQuery(app.todos.where({ completed: false }))\n * ```\n *\n * Requires `KoraProvider` to be initialized with the `app` prop.\n * Throws if used outside of `KoraProvider` or without an `app` prop.\n *\n * @returns The KoraApp instance, typed as `T`\n */\nexport function useApp<T extends KoraAppLike = KoraAppLike>(): T {\n\tconst { app } = useKoraContext()\n\tif (!app) {\n\t\tthrow new Error(\n\t\t\t'useApp() requires KoraProvider to be initialized with an \"app\" prop. ' +\n\t\t\t\t'Pass your createApp() result to <KoraProvider app={app}>.',\n\t\t)\n\t}\n\treturn app as T\n}\n","import type { CollectionRecord, QueryBuilder } from '@korajs/store'\nimport { useMemo, useRef, useSyncExternalStore } from 'react'\nimport { QueryStore } from '../query-store/query-store'\nimport type { UseQueryOptions } from '../types'\n\n/**\n * Frozen empty array returned when the query is disabled or before data loads.\n * Same reference prevents unnecessary re-renders.\n */\nconst EMPTY_ARRAY: readonly unknown[] = Object.freeze([])\n\nconst noopSubscribe = (_onStoreChange: () => void): (() => void) => {\n\treturn () => {}\n}\n\n/**\n * React hook for reactive queries against the local Kora store.\n *\n * Returns data synchronously from the local store — no loading spinners needed.\n * Re-renders automatically when the query results change due to mutations.\n * Uses `useSyncExternalStore` for React 18+ concurrent mode safety.\n *\n * The generic parameter `T` is inferred from the QueryBuilder, providing\n * full type safety when used with typed collection accessors.\n *\n * @param query - A QueryBuilder instance (e.g., `app.todos.where({ done: false })`)\n * @param options - Optional configuration (e.g., `{ enabled: false }` to skip the query)\n * @returns Readonly array of matching records\n *\n * @example\n * ```typescript\n * const todos = useQuery(app.todos.where({ completed: false }).orderBy('createdAt'))\n * // todos is typed as readonly InferRecord<typeof todoFields>[]\n * ```\n */\nexport function useQuery<T = CollectionRecord>(\n\tquery: QueryBuilder<T>,\n\toptions?: UseQueryOptions,\n): readonly T[] {\n\tconst enabled = options?.enabled !== false\n\n\t// Compute a stable key from the query descriptor\n\tconst descriptorKey = JSON.stringify(query.getDescriptor())\n\n\t// Track the current QueryStore instance\n\tconst queryStoreRef = useRef<QueryStore<T> | null>(null)\n\tconst prevKeyRef = useRef<string | null>(null)\n\n\t// Create or reuse a QueryStore when the descriptor changes\n\tconst queryStore = useMemo(() => {\n\t\tif (!enabled) {\n\t\t\t// Destroy previous if it exists\n\t\t\tif (queryStoreRef.current) {\n\t\t\t\tqueryStoreRef.current.destroy()\n\t\t\t\tqueryStoreRef.current = null\n\t\t\t}\n\t\t\tprevKeyRef.current = null\n\t\t\treturn null\n\t\t}\n\n\t\t// If descriptor changed, destroy previous and create new\n\t\tif (prevKeyRef.current !== descriptorKey) {\n\t\t\tif (queryStoreRef.current) {\n\t\t\t\tqueryStoreRef.current.destroy()\n\t\t\t}\n\t\t\tconst newStore = new QueryStore<T>(query)\n\t\t\tqueryStoreRef.current = newStore\n\t\t\tprevKeyRef.current = descriptorKey\n\t\t\treturn newStore\n\t\t}\n\n\t\treturn queryStoreRef.current\n\t}, [descriptorKey, enabled, query])\n\n\t// No useEffect cleanup needed: QueryStore's subscribe/unsubscribe cycle\n\t// manages the underlying subscription lifetime. When the last listener\n\t// detaches (on unmount), the subscription auto-stops. This also makes\n\t// the hook resilient to React StrictMode's double-mount cycle.\n\n\tconst disabledGetSnapshot = (): readonly T[] => EMPTY_ARRAY as readonly T[]\n\n\treturn useSyncExternalStore(\n\t\tqueryStore ? queryStore.subscribe : noopSubscribe,\n\t\tqueryStore ? queryStore.getSnapshot : disabledGetSnapshot,\n\t)\n}\n","import type { CollectionRecord, QueryBuilder } from '@korajs/store'\n\n/**\n * Frozen empty array returned as the initial snapshot before any data loads.\n * Same reference every time prevents infinite re-render loops with useSyncExternalStore.\n */\nconst EMPTY_ARRAY: readonly unknown[] = Object.freeze([])\n\n/**\n * Bridges the async QueryBuilder.subscribe() API with the synchronous\n * getSnapshot() required by React's useSyncExternalStore.\n *\n * Uses a lazy subscription model: the underlying query subscription starts\n * when the first listener attaches (via useSyncExternalStore's subscribe)\n * and stops when the last listener detaches. This makes QueryStore resilient\n * to React StrictMode's double-mount cycle, where useEffect cleanup fires\n * between mount and remount.\n *\n * Generic parameter `T` defaults to `CollectionRecord` for backward compatibility.\n */\nexport class QueryStore<T = CollectionRecord> {\n\tprivate snapshot: readonly T[] = EMPTY_ARRAY as readonly T[]\n\tprivate listeners = new Set<() => void>()\n\tprivate unsubscribeQuery: (() => void) | null = null\n\tprivate active = false\n\tprivate readonly queryBuilder: QueryBuilder<T>\n\n\tconstructor(queryBuilder: QueryBuilder<T>) {\n\t\tthis.queryBuilder = queryBuilder\n\t}\n\n\t/**\n\t * Subscribe to snapshot changes. Compatible with useSyncExternalStore.\n\t *\n\t * Lazily starts the underlying query subscription when the first listener\n\t * attaches, and stops it when the last listener detaches. This allows\n\t * React StrictMode to unmount/remount without permanently killing the subscription.\n\t *\n\t * @returns Unsubscribe function\n\t */\n\tsubscribe = (onStoreChange: () => void): (() => void) => {\n\t\tthis.listeners.add(onStoreChange)\n\n\t\t// Start the underlying query subscription when the first listener attaches\n\t\tif (!this.active) {\n\t\t\tthis.startSubscription()\n\t\t}\n\n\t\treturn () => {\n\t\t\tthis.listeners.delete(onStoreChange)\n\t\t\t// Stop the underlying subscription when the last listener detaches.\n\t\t\t// This ensures cleanup on unmount without needing a useEffect.\n\t\t\tif (this.listeners.size === 0) {\n\t\t\t\tthis.stopSubscription()\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the current snapshot synchronously. Compatible with useSyncExternalStore.\n\t * Returns EMPTY_ARRAY before the first async fetch completes.\n\t */\n\tgetSnapshot = (): readonly T[] => {\n\t\treturn this.snapshot\n\t}\n\n\t/**\n\t * Clean up the underlying subscription and release resources.\n\t * Called by useMemo when the query descriptor changes.\n\t */\n\tdestroy(): void {\n\t\tthis.stopSubscription()\n\t\tthis.listeners.clear()\n\t\tthis.snapshot = EMPTY_ARRAY as readonly T[]\n\t}\n\n\tprivate startSubscription(): void {\n\t\tthis.active = true\n\t\tthis.unsubscribeQuery = this.queryBuilder.subscribe((results) => {\n\t\t\tif (!this.active) return\n\t\t\tconst newSnapshot = Object.freeze([...results])\n\t\t\tthis.snapshot = newSnapshot\n\t\t\tthis.notifyListeners()\n\t\t})\n\t}\n\n\tprivate stopSubscription(): void {\n\t\tthis.active = false\n\t\tif (this.unsubscribeQuery) {\n\t\t\tthis.unsubscribeQuery()\n\t\t\tthis.unsubscribeQuery = null\n\t\t}\n\t}\n\n\tprivate notifyListeners(): void {\n\t\tfor (const listener of this.listeners) {\n\t\t\tlistener()\n\t\t}\n\t}\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { UseMutationResult } from '../types'\n\n/**\n * React hook for performing mutations against the local Kora store.\n *\n * Returns `mutate` for fire-and-forget usage (optimistic) and `mutateAsync`\n * for when you need to await the result. Tracks loading and error state.\n *\n * @param mutationFn - An async function to execute (e.g., `app.todos.insert`)\n * @returns Object with mutate, mutateAsync, isLoading, error, and reset\n *\n * @example\n * ```typescript\n * const { mutate } = useMutation(app.todos.insert)\n * mutate({ title: 'New todo' }) // fire-and-forget\n * ```\n */\nexport function useMutation<TData, TArgs extends unknown[]>(\n\tmutationFn: (...args: TArgs) => Promise<TData>,\n): UseMutationResult<TData, TArgs> {\n\tconst [state, setState] = useState<{ isLoading: boolean; error: Error | null }>({\n\t\tisLoading: false,\n\t\terror: null,\n\t})\n\n\t// Track mounted state to avoid state updates after unmount\n\tconst mountedRef = useRef(true)\n\tuseEffect(() => {\n\t\tmountedRef.current = true\n\t\treturn () => {\n\t\t\tmountedRef.current = false\n\t\t}\n\t}, [])\n\n\t// Keep latest mutation function in a ref to avoid stale closures\n\tconst fnRef = useRef(mutationFn)\n\tfnRef.current = mutationFn\n\n\tconst mutateAsync = useCallback(async (...args: TArgs): Promise<TData> => {\n\t\tif (mountedRef.current) {\n\t\t\tsetState({ isLoading: true, error: null })\n\t\t}\n\t\ttry {\n\t\t\tconst result = await fnRef.current(...args)\n\t\t\tif (mountedRef.current) {\n\t\t\t\tsetState({ isLoading: false, error: null })\n\t\t\t}\n\t\t\treturn result\n\t\t} catch (err) {\n\t\t\tconst error = err instanceof Error ? err : new Error(String(err))\n\t\t\tif (mountedRef.current) {\n\t\t\t\tsetState({ isLoading: false, error })\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}, [])\n\n\tconst mutate = useCallback(\n\t\t(...args: TArgs): void => {\n\t\t\tmutateAsync(...args).catch(() => {\n\t\t\t\t// Fire-and-forget: error is captured in state, no unhandled rejection\n\t\t\t})\n\t\t},\n\t\t[mutateAsync],\n\t)\n\n\tconst reset = useCallback((): void => {\n\t\tif (mountedRef.current) {\n\t\t\tsetState({ isLoading: false, error: null })\n\t\t}\n\t}, [])\n\n\treturn {\n\t\tmutate,\n\t\tmutateAsync,\n\t\tisLoading: state.isLoading,\n\t\terror: state.error,\n\t\treset,\n\t}\n}\n","import type { SyncStatusInfo } from '@korajs/sync'\nimport { useCallback, useEffect, useRef, useSyncExternalStore } from 'react'\nimport { useKoraContext } from '../context/kora-context'\n\nconst POLL_INTERVAL_MS = 500\n\n/** Default status returned when no sync engine is configured */\nconst OFFLINE_STATUS: SyncStatusInfo = Object.freeze({\n\tstatus: 'offline',\n\tpendingOperations: 0,\n\tlastSyncedAt: null,\n\tlastSuccessfulPush: null,\n\tlastSuccessfulPull: null,\n\tconflicts: 0,\n})\n\n/**\n * React hook for monitoring the sync engine's connection status.\n *\n * Polls the SyncEngine at ~500ms intervals and re-renders only when\n * the status actually changes. Returns a default offline status when\n * no sync engine is configured.\n *\n * @returns Current sync status information\n *\n * @example\n * ```typescript\n * const status = useSyncStatus()\n * // status.status: 'connected' | 'syncing' | 'synced' | 'offline' | 'error'\n * // status.pendingOperations: number\n * // status.lastSyncedAt: number | null\n * ```\n */\nexport function useSyncStatus(): SyncStatusInfo {\n\tconst { syncEngine } = useKoraContext()\n\n\t// Cache the latest status snapshot for stable references\n\tconst snapshotRef = useRef<SyncStatusInfo>(OFFLINE_STATUS)\n\tconst serializedRef = useRef<string>(JSON.stringify(OFFLINE_STATUS))\n\n\tconst subscribe = useCallback(\n\t\t(onStoreChange: () => void): (() => void) => {\n\t\t\tif (!syncEngine) return () => {}\n\n\t\t\t// Poll the sync engine status at regular intervals\n\t\t\tconst intervalId = setInterval(() => {\n\t\t\t\tconst newStatus = syncEngine.getStatus()\n\t\t\t\tconst newSerialized = JSON.stringify(newStatus)\n\n\t\t\t\t// Only notify React if status actually changed\n\t\t\t\tif (newSerialized !== serializedRef.current) {\n\t\t\t\t\tsnapshotRef.current = newStatus\n\t\t\t\t\tserializedRef.current = newSerialized\n\t\t\t\t\tonStoreChange()\n\t\t\t\t}\n\t\t\t}, POLL_INTERVAL_MS)\n\n\t\t\t// Do an immediate check\n\t\t\tconst initialStatus = syncEngine.getStatus()\n\t\t\tconst initialSerialized = JSON.stringify(initialStatus)\n\t\t\tif (initialSerialized !== serializedRef.current) {\n\t\t\t\tsnapshotRef.current = initialStatus\n\t\t\t\tserializedRef.current = initialSerialized\n\t\t\t\tonStoreChange()\n\t\t\t}\n\n\t\t\treturn () => {\n\t\t\t\tclearInterval(intervalId)\n\t\t\t}\n\t\t},\n\t\t[syncEngine],\n\t)\n\n\tconst getSnapshot = useCallback((): SyncStatusInfo => {\n\t\treturn snapshotRef.current\n\t}, [])\n\n\t// Reset snapshot when syncEngine changes\n\tuseEffect(() => {\n\t\tif (!syncEngine) {\n\t\t\tsnapshotRef.current = OFFLINE_STATUS\n\t\t\tserializedRef.current = JSON.stringify(OFFLINE_STATUS)\n\t\t}\n\t}, [syncEngine])\n\n\treturn useSyncExternalStore(subscribe, getSnapshot)\n}\n","import type { CollectionAccessor } from '@korajs/store'\nimport { useMemo } from 'react'\nimport { useKoraContext } from '../context/kora-context'\n\n/**\n * React hook that returns a CollectionAccessor for the given collection name.\n * Convenience hook for accessing a collection without going through the store directly.\n *\n * @param name - The collection name (must match a collection in the schema)\n * @returns CollectionAccessor with insert, findById, update, delete, and where methods\n *\n * @example\n * ```typescript\n * const todos = useCollection('todos')\n * await todos.insert({ title: 'New todo' })\n * ```\n */\nexport function useCollection(name: string): CollectionAccessor {\n\tconst { store } = useKoraContext()\n\n\treturn useMemo(() => {\n\t\treturn store.collection(name)\n\t}, [store, name])\n}\n","import type { CollectionAccessor } from '@korajs/store'\nimport type { AwarenessState, CursorInfo } from '@korajs/sync'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport * as Y from 'yjs'\nimport { useKoraContext } from '../context/kora-context'\nimport type { UseRichTextResult } from '../types'\n\nconst LOAD_ORIGIN = 'kora-load'\nconst TEXT_KEY = 'content'\nconst COMPACT_AFTER_DELTAS = 20\n\n/**\n * Binds a richtext field to a shared Yjs document for editor integration.\n */\nexport function useRichText(\n\tcollectionName: string,\n\trecordId: string,\n\tfieldName: string,\n): UseRichTextResult {\n\tconst { store, syncEngine } = useKoraContext()\n\tconst collection = useMemo<CollectionAccessor>(\n\t\t() => store.collection(collectionName),\n\t\t[store, collectionName],\n\t)\n\tconst [doc] = useState(() => new Y.Doc())\n\tconst [ready, setReady] = useState(false)\n\tconst [error, setError] = useState<Error | null>(null)\n\tconst [canUndo, setCanUndo] = useState(false)\n\tconst [canRedo, setCanRedo] = useState(false)\n\tconst [cursors, setCursors] = useState<CursorInfo[]>([])\n\tconst baseUpdateRef = useRef<Uint8Array | null>(null)\n\tconst pendingDeltasRef = useRef<Uint8Array[]>([])\n\n\tconst text = useMemo(() => doc.getText(TEXT_KEY), [doc])\n\tconst undoManager = useMemo(() => new Y.UndoManager(text), [text])\n\n\tconst syncHistoryState = useCallback(() => {\n\t\tsetCanUndo(undoManager.undoStack.length > 0)\n\t\tsetCanRedo(undoManager.redoStack.length > 0)\n\t}, [undoManager])\n\n\tconst undo = useCallback(() => {\n\t\tundoManager.undo()\n\t\tsyncHistoryState()\n\t}, [syncHistoryState, undoManager])\n\n\tconst redo = useCallback(() => {\n\t\tundoManager.redo()\n\t\tsyncHistoryState()\n\t}, [syncHistoryState, undoManager])\n\n\tuseEffect(() => {\n\t\tlet disposed = false\n\n\t\tconst initialize = async (): Promise<void> => {\n\t\t\tsetReady(false)\n\t\t\tsetError(null)\n\n\t\t\ttry {\n\t\t\t\tconst record = await collection.findById(recordId)\n\t\t\t\tif (disposed) return\n\n\t\t\t\tdoc.transact(() => {\n\t\t\t\t\tconst target = doc.getText(TEXT_KEY)\n\t\t\t\t\ttarget.delete(0, target.length)\n\t\t\t\t}, LOAD_ORIGIN)\n\n\t\t\t\tconst encoded = encodeRichtextInput(record?.[fieldName])\n\t\t\t\tbaseUpdateRef.current = encoded\n\t\t\t\tpendingDeltasRef.current = []\n\t\t\t\tif (encoded) {\n\t\t\t\t\tY.applyUpdate(doc, encoded, LOAD_ORIGIN)\n\t\t\t\t}\n\n\t\t\t\tsetReady(true)\n\t\t\t} catch (cause) {\n\t\t\t\tif (disposed) return\n\t\t\t\tsetError(cause instanceof Error ? cause : new Error(String(cause)))\n\t\t\t}\n\t\t}\n\n\t\tconst persist = async (_update: Uint8Array, origin: unknown): Promise<void> => {\n\t\t\tsyncHistoryState()\n\t\t\tif (origin === LOAD_ORIGIN) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tpendingDeltasRef.current.push(_update)\n\t\t\tconst snapshot = composeRichtextSnapshot(baseUpdateRef.current, pendingDeltasRef.current)\n\n\t\t\tif (pendingDeltasRef.current.length >= COMPACT_AFTER_DELTAS) {\n\t\t\t\tbaseUpdateRef.current = snapshot\n\t\t\t\tpendingDeltasRef.current = []\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait collection.update(recordId, {\n\t\t\t\t\t[fieldName]: snapshot,\n\t\t\t\t})\n\t\t\t} catch (cause) {\n\t\t\t\tif (!disposed) {\n\t\t\t\t\tsetError(cause instanceof Error ? cause : new Error(String(cause)))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tdoc.on('update', persist)\n\t\tvoid initialize()\n\n\t\tsyncHistoryState()\n\n\t\treturn () => {\n\t\t\tdisposed = true\n\t\t\tdoc.off('update', persist)\n\t\t\tundoManager.destroy()\n\t\t\tbaseUpdateRef.current = null\n\t\t\tpendingDeltasRef.current = []\n\t\t}\n\t}, [collection, doc, fieldName, recordId, syncHistoryState, undoManager])\n\n\t// Track remote collaborators' cursors for this specific field\n\tuseEffect(() => {\n\t\tif (!syncEngine) return\n\n\t\tconst awareness = syncEngine.getAwarenessManager()\n\t\tconst localClientId = awareness.clientId\n\n\t\tconst updateCursors = (): void => {\n\t\t\tconst states = awareness.getStates()\n\t\t\tconst fieldCursors: CursorInfo[] = []\n\n\t\t\tfor (const [clientId, state] of states) {\n\t\t\t\tif (clientId === localClientId) continue\n\t\t\t\tif (!state.cursor) continue\n\t\t\t\t// Only include cursors for this specific field\n\t\t\t\tif (\n\t\t\t\t\tstate.cursor.collection !== collectionName ||\n\t\t\t\t\tstate.cursor.recordId !== recordId ||\n\t\t\t\t\tstate.cursor.field !== fieldName\n\t\t\t\t) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfieldCursors.push({\n\t\t\t\t\tclientId,\n\t\t\t\t\tuserName: state.user.name,\n\t\t\t\t\tcolor: state.user.color,\n\t\t\t\t\tanchor: state.cursor.anchor,\n\t\t\t\t\thead: state.cursor.head,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tsetCursors(fieldCursors)\n\t\t}\n\n\t\tconst unsubscribe = awareness.on('change', () => {\n\t\t\tupdateCursors()\n\t\t})\n\n\t\t// Initial check\n\t\tupdateCursors()\n\n\t\treturn unsubscribe\n\t}, [syncEngine, collectionName, recordId, fieldName])\n\n\treturn { doc, text, undo, redo, canUndo, canRedo, ready, error, cursors }\n}\n\nfunction encodeRichtextInput(value: unknown): Uint8Array | null {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\tif (typeof value === 'string') {\n\t\tconst doc = new Y.Doc()\n\t\tdoc.getText(TEXT_KEY).insert(0, value)\n\t\treturn Y.encodeStateAsUpdate(doc)\n\t}\n\n\tif (value instanceof Uint8Array) {\n\t\treturn value\n\t}\n\n\tif (value instanceof ArrayBuffer) {\n\t\treturn new Uint8Array(value)\n\t}\n\n\t// Handle Node.js Buffer without requiring @types/node\n\tif (typeof globalThis !== 'undefined' && 'Buffer' in globalThis) {\n\t\tconst BufferCtor = (globalThis as Record<string, unknown>).Buffer as {\n\t\t\tisBuffer(v: unknown): v is { buffer: ArrayBuffer; byteOffset: number; byteLength: number }\n\t\t}\n\t\tif (BufferCtor.isBuffer(value)) {\n\t\t\treturn new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n\t\t}\n\t}\n\n\tthrow new Error('Richtext record value must be a string, Uint8Array, ArrayBuffer, or null.')\n}\n\nfunction composeRichtextSnapshot(base: Uint8Array | null, deltas: Uint8Array[]): Uint8Array {\n\tconst doc = new Y.Doc()\n\tif (base) {\n\t\tY.applyUpdate(doc, base)\n\t}\n\n\tfor (const delta of deltas) {\n\t\tY.applyUpdate(doc, delta)\n\t}\n\n\treturn Y.encodeStateAsUpdate(doc)\n}\n"],"mappings":"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","names":["import_react","EMPTY_ARRAY","import_react","import_react","import_react","import_react"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/context/kora-context.ts","../src/hooks/use-app.ts","../src/hooks/use-query.ts","../src/query-store/query-store.ts","../src/hooks/use-mutation.ts","../src/hooks/use-sync-status.ts","../src/hooks/use-collection.ts","../src/hooks/use-rich-text.ts"],"sourcesContent":["// @korajs/react — public API\n// Every export here is a public API commitment. Be explicit.\n\n// === Types ===\nexport type {\n\tKoraAppLike,\n\tKoraContextValue,\n\tKoraProviderProps,\n\tUseQueryOptions,\n\tUseMutationOptions,\n\tUseMutationResult,\n\tUseRichTextResult,\n} from './types'\n\n// === Context ===\nexport { KoraProvider } from './context/kora-context'\n\n// === Hooks ===\nexport { useApp } from './hooks/use-app'\nexport { useQuery } from './hooks/use-query'\nexport { useMutation } from './hooks/use-mutation'\nexport { useSyncStatus } from './hooks/use-sync-status'\nexport { useCollection } from './hooks/use-collection'\nexport { useRichText } from './hooks/use-rich-text'\nexport type { UseRichTextOptions } from './hooks/use-rich-text'\n","import type { Store } from '@korajs/store'\nimport type { SyncEngine } from '@korajs/sync'\nimport { createContext, createElement, useContext, useEffect, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport type { KoraContextValue, KoraProviderProps } from '../types'\n\nconst KoraContext = createContext<KoraContextValue | null>(null)\n\n/**\n * Provides Kora store and optional sync engine to all child components.\n * Must wrap any component that uses Kora hooks (useQuery, useMutation, etc.).\n *\n * Accepts either an `app` prop (recommended) or explicit `store` + `syncEngine` props.\n *\n * When using the `app` prop, KoraProvider waits for `app.ready` before rendering\n * children. A `fallback` prop can be provided to show content while initializing.\n *\n * @example\n * ```typescript\n * // Recommended: pass the app object directly\n * const app = createApp({ schema })\n * <KoraProvider app={app}><App /></KoraProvider>\n *\n * // Advanced: pass store and syncEngine explicitly\n * <KoraProvider store={store} syncEngine={syncEngine}><App /></KoraProvider>\n * ```\n */\nfunction KoraProvider({\n\tapp,\n\tstore,\n\tsyncEngine,\n\tfallback,\n\tchildren,\n}: KoraProviderProps): ReactNode {\n\tconst [resolvedStore, setResolvedStore] = useState<Store | null>(store ?? null)\n\tconst [resolvedSync, setResolvedSync] = useState<SyncEngine | null>(syncEngine ?? null)\n\t// If no app prop, we're using the store prop and are ready immediately\n\tconst [ready, setReady] = useState(!app)\n\tconst [initError, setInitError] = useState<Error | null>(null)\n\n\tuseEffect(() => {\n\t\tif (!app) return\n\t\tlet cancelled = false\n\t\tapp.ready\n\t\t\t.then(() => {\n\t\t\t\tif (cancelled) return\n\t\t\t\tsetResolvedStore(app.getStore())\n\t\t\t\tsetResolvedSync(app.getSyncEngine())\n\t\t\t\tsetReady(true)\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (cancelled) return\n\t\t\t\tconst err = error instanceof Error ? error : new Error(String(error))\n\t\t\t\tconsole.error('[Kora] Initialization failed:', err)\n\t\t\t\tsetInitError(err)\n\t\t\t})\n\t\treturn () => {\n\t\t\tcancelled = true\n\t\t}\n\t}, [app])\n\n\tif (initError) {\n\t\treturn createElement(\n\t\t\t'div',\n\t\t\t{ style: { color: 'red', padding: '1rem', fontFamily: 'monospace' } },\n\t\t\tcreateElement('strong', null, 'Kora initialization error: '),\n\t\t\tinitError.message,\n\t\t)\n\t}\n\n\tif (!ready) {\n\t\treturn (fallback ?? null) as ReactNode\n\t}\n\n\tif (!resolvedStore) {\n\t\tthrow new Error(\n\t\t\t'KoraProvider requires either an \"app\" or \"store\" prop. ' +\n\t\t\t\t'Pass a KoraApp from createApp() or a Store instance.',\n\t\t)\n\t}\n\n\tconst value: KoraContextValue = {\n\t\tstore: resolvedStore,\n\t\tsyncEngine: resolvedSync,\n\t\tapp: app ?? null,\n\t\tevents: app?.events ?? null,\n\t\tsubscribeSyncStatus: app?.sync?.subscribeStatus ?? null,\n\t}\n\treturn createElement(KoraContext.Provider, { value }, children)\n}\n\n/**\n * Internal hook to access the Kora context.\n * Throws if used outside of a KoraProvider.\n */\nfunction useKoraContext(): KoraContextValue {\n\tconst context = useContext(KoraContext)\n\tif (context === null) {\n\t\tthrow new Error(\n\t\t\t'useKoraContext must be used within a <KoraProvider>. ' +\n\t\t\t\t'Wrap your component tree with <KoraProvider store={store}>.',\n\t\t)\n\t}\n\treturn context\n}\n\nexport { KoraProvider, useKoraContext }\n","import { useKoraContext } from '../context/kora-context'\nimport type { KoraAppLike } from '../types'\n\n/**\n * React hook that returns the Kora app instance from context.\n *\n * Use the generic parameter to cast to your typed app for full type inference:\n *\n * ```typescript\n * // In your app setup:\n * export const app = createApp({ schema: mySchema })\n * export type App = typeof app\n *\n * // In components:\n * const app = useApp<App>()\n * app.todos.insert({ title: 'Hello' }) // fully typed\n * const todos = useQuery(app.todos.where({ completed: false }))\n * ```\n *\n * Requires `KoraProvider` to be initialized with the `app` prop.\n * Throws if used outside of `KoraProvider` or without an `app` prop.\n *\n * @returns The KoraApp instance, typed as `T`\n */\nexport function useApp<T extends KoraAppLike = KoraAppLike>(): T {\n\tconst { app } = useKoraContext()\n\tif (!app) {\n\t\tthrow new Error(\n\t\t\t'useApp() requires KoraProvider to be initialized with an \"app\" prop. ' +\n\t\t\t\t'Pass your createApp() result to <KoraProvider app={app}>.',\n\t\t)\n\t}\n\treturn app as T\n}\n","import type { CollectionRecord, QueryBuilder } from '@korajs/store'\nimport { useMemo, useRef, useSyncExternalStore } from 'react'\nimport { QueryStore } from '../query-store/query-store'\nimport type { UseQueryOptions } from '../types'\n\nconst APP_NOT_READY_CODE = 'APP_NOT_READY'\n\nfunction assertQueryReady(query: QueryBuilder<unknown>): void {\n\tconst descriptor = query.getDescriptor()\n\tif (descriptor.collection === '__pending__') {\n\t\tconst err = new Error(\n\t\t\t'Cannot use useQuery() before app.ready. Await app.ready or wrap your UI in <KoraProvider app={app}>.',\n\t\t)\n\t\terr.name = 'AppNotReadyError'\n\t\tObject.assign(err, { code: APP_NOT_READY_CODE })\n\t\tthrow err\n\t}\n}\n\n/**\n * Frozen empty array returned when the query is disabled or before data loads.\n * Same reference prevents unnecessary re-renders.\n */\nconst EMPTY_ARRAY: readonly unknown[] = Object.freeze([])\n\nconst noopSubscribe = (_onStoreChange: () => void): (() => void) => {\n\treturn () => {}\n}\n\n/**\n * React hook for reactive queries against the local Kora store.\n *\n * Returns data synchronously from the local store — no loading spinners needed.\n * Re-renders automatically when the query results change due to mutations.\n * Uses `useSyncExternalStore` for React 18+ concurrent mode safety.\n *\n * The generic parameter `T` is inferred from the QueryBuilder, providing\n * full type safety when used with typed collection accessors.\n *\n * @param query - A QueryBuilder instance (e.g., `app.todos.where({ done: false })`)\n * @param options - Optional configuration (e.g., `{ enabled: false }` to skip the query)\n * @returns Readonly array of matching records\n *\n * @example\n * ```typescript\n * const todos = useQuery(app.todos.where({ completed: false }).orderBy('createdAt'))\n * // todos is typed as readonly InferRecord<typeof todoFields>[]\n * ```\n */\nexport function useQuery<T = CollectionRecord>(\n\tquery: QueryBuilder<T>,\n\toptions?: UseQueryOptions,\n): readonly T[] {\n\tconst enabled = options?.enabled !== false\n\n\tif (enabled) {\n\t\tassertQueryReady(query)\n\t}\n\n\t// Compute a stable key from the query descriptor\n\tconst descriptorKey = JSON.stringify(query.getDescriptor())\n\n\t// Track the current QueryStore instance\n\tconst queryStoreRef = useRef<QueryStore<T> | null>(null)\n\tconst prevKeyRef = useRef<string | null>(null)\n\n\t// Create or reuse a QueryStore when the descriptor changes\n\tconst queryStore = useMemo(() => {\n\t\tif (!enabled) {\n\t\t\t// Destroy previous if it exists\n\t\t\tif (queryStoreRef.current) {\n\t\t\t\tqueryStoreRef.current.destroy()\n\t\t\t\tqueryStoreRef.current = null\n\t\t\t}\n\t\t\tprevKeyRef.current = null\n\t\t\treturn null\n\t\t}\n\n\t\t// If descriptor changed, destroy previous and create new\n\t\tif (prevKeyRef.current !== descriptorKey) {\n\t\t\tif (queryStoreRef.current) {\n\t\t\t\tqueryStoreRef.current.destroy()\n\t\t\t}\n\t\t\tconst newStore = new QueryStore<T>(query)\n\t\t\tqueryStoreRef.current = newStore\n\t\t\tprevKeyRef.current = descriptorKey\n\t\t\treturn newStore\n\t\t}\n\n\t\treturn queryStoreRef.current\n\t}, [descriptorKey, enabled, query])\n\n\t// No useEffect cleanup needed: QueryStore's subscribe/unsubscribe cycle\n\t// manages the underlying subscription lifetime. When the last listener\n\t// detaches (on unmount), the subscription auto-stops. This also makes\n\t// the hook resilient to React StrictMode's double-mount cycle.\n\n\tconst disabledGetSnapshot = (): readonly T[] => EMPTY_ARRAY as readonly T[]\n\n\t// The query object is deliberately excluded from the dependency array.\n\t// QueryBuilder instances are ephemeral (created on every render when\n\t// developers use inline `app.todos.where({...})`). Using it as a dep\n\t// would destroy and recreate the QueryStore on every render, causing\n\t// subscription storms. Instead, we only react to the stable descriptor\n\t// JSON key, which captures the actual query parameters.\n\treturn useSyncExternalStore(\n\t\tqueryStore ? queryStore.subscribe : noopSubscribe,\n\t\tqueryStore ? queryStore.getSnapshot : disabledGetSnapshot,\n\t)\n}\n","import type { CollectionRecord, QueryBuilder } from '@korajs/store'\n\n/**\n * Frozen empty array returned as the initial snapshot before any data loads.\n * Same reference every time prevents infinite re-render loops with useSyncExternalStore.\n */\nconst EMPTY_ARRAY: readonly unknown[] = Object.freeze([])\n\n/**\n * Bridges the async QueryBuilder.subscribe() API with the synchronous\n * getSnapshot() required by React's useSyncExternalStore.\n *\n * Uses a lazy subscription model: the underlying query subscription starts\n * when the first listener attaches (via useSyncExternalStore's subscribe)\n * and stops when the last listener detaches. This makes QueryStore resilient\n * to React StrictMode's double-mount cycle, where useEffect cleanup fires\n * between mount and remount.\n *\n * Generic parameter `T` defaults to `CollectionRecord` for backward compatibility.\n */\nexport class QueryStore<T = CollectionRecord> {\n\tprivate snapshot: readonly T[] = EMPTY_ARRAY as readonly T[]\n\tprivate listeners = new Set<() => void>()\n\tprivate unsubscribeQuery: (() => void) | null = null\n\tprivate active = false\n\tprivate readonly queryBuilder: QueryBuilder<T>\n\n\tconstructor(queryBuilder: QueryBuilder<T>) {\n\t\tthis.queryBuilder = queryBuilder\n\t}\n\n\t/**\n\t * Subscribe to snapshot changes. Compatible with useSyncExternalStore.\n\t *\n\t * Lazily starts the underlying query subscription when the first listener\n\t * attaches, and stops it when the last listener detaches. This allows\n\t * React StrictMode to unmount/remount without permanently killing the subscription.\n\t *\n\t * @returns Unsubscribe function\n\t */\n\tsubscribe = (onStoreChange: () => void): (() => void) => {\n\t\tthis.listeners.add(onStoreChange)\n\n\t\t// Start the underlying query subscription when the first listener attaches\n\t\tif (!this.active) {\n\t\t\tthis.startSubscription()\n\t\t}\n\n\t\treturn () => {\n\t\t\tthis.listeners.delete(onStoreChange)\n\t\t\t// Stop the underlying subscription when the last listener detaches.\n\t\t\t// This ensures cleanup on unmount without needing a useEffect.\n\t\t\tif (this.listeners.size === 0) {\n\t\t\t\tthis.stopSubscription()\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the current snapshot synchronously. Compatible with useSyncExternalStore.\n\t * Returns EMPTY_ARRAY before the first async fetch completes.\n\t */\n\tgetSnapshot = (): readonly T[] => {\n\t\treturn this.snapshot\n\t}\n\n\t/**\n\t * Clean up the underlying subscription and release resources.\n\t * Called by useMemo when the query descriptor changes.\n\t */\n\tdestroy(): void {\n\t\tthis.stopSubscription()\n\t\tthis.listeners.clear()\n\t\tthis.snapshot = EMPTY_ARRAY as readonly T[]\n\t}\n\n\tprivate startSubscription(): void {\n\t\tthis.active = true\n\t\tthis.unsubscribeQuery = this.queryBuilder.subscribe((results) => {\n\t\t\tif (!this.active) return\n\t\t\tconst newSnapshot = Object.freeze([...results])\n\t\t\tthis.snapshot = newSnapshot\n\t\t\tthis.notifyListeners()\n\t\t})\n\t}\n\n\tprivate stopSubscription(): void {\n\t\tthis.active = false\n\t\tif (this.unsubscribeQuery) {\n\t\t\tthis.unsubscribeQuery()\n\t\t\tthis.unsubscribeQuery = null\n\t\t}\n\t}\n\n\tprivate notifyListeners(): void {\n\t\tfor (const listener of this.listeners) {\n\t\t\tlistener()\n\t\t}\n\t}\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { UseMutationOptions, UseMutationResult } from '../types'\n\n/**\n * React hook for performing mutations against the local Kora store.\n *\n * Returns `mutate` for fire-and-forget usage and `mutateAsync` when you need\n * to await the result. Optional `onMutate` / `onRollback` support optimistic\n * UI updates that revert if the mutation throws.\n *\n * @param mutationFn - An async function to execute (e.g., `app.todos.insert`)\n * @param options - Optional optimistic/rollback and lifecycle callbacks\n * @returns Object with mutate, mutateAsync, isLoading, error, and reset\n *\n * @example\n * ```typescript\n * const { mutate } = useMutation(app.todos.insert, {\n * onMutate: (data) => {\n * const previous = todos\n * setTodos((list) => [...list, { id: 'temp', ...data }])\n * return previous\n * },\n * onRollback: (previous) => setTodos(previous),\n * })\n * ```\n */\nexport function useMutation<TData, TArgs extends unknown[], TContext = void>(\n\tmutationFn: (...args: TArgs) => Promise<TData>,\n\toptions?: UseMutationOptions<TData, TArgs, TContext>,\n): UseMutationResult<TData, TArgs> {\n\tconst [state, setState] = useState<{ isLoading: boolean; error: Error | null }>({\n\t\tisLoading: false,\n\t\terror: null,\n\t})\n\n\tconst mountedRef = useRef(true)\n\tuseEffect(() => {\n\t\tmountedRef.current = true\n\t\treturn () => {\n\t\t\tmountedRef.current = false\n\t\t}\n\t}, [])\n\n\tconst fnRef = useRef(mutationFn)\n\tfnRef.current = mutationFn\n\n\tconst optionsRef = useRef(options)\n\toptionsRef.current = options\n\n\tconst mutateAsync = useCallback(async (...args: TArgs): Promise<TData> => {\n\t\tconst opts = optionsRef.current\n\t\tlet context: TContext | undefined\n\n\t\tif (mountedRef.current) {\n\t\t\tsetState({ isLoading: true, error: null })\n\t\t}\n\n\t\ttry {\n\t\t\tif (opts?.onMutate) {\n\t\t\t\tcontext = await opts.onMutate(...args)\n\t\t\t}\n\n\t\t\tconst result = await fnRef.current(...args)\n\n\t\t\tif (mountedRef.current) {\n\t\t\t\tsetState({ isLoading: false, error: null })\n\t\t\t}\n\t\t\topts?.onSuccess?.(result, ...args)\n\t\t\topts?.onSettled?.(result, null, ...args)\n\t\t\treturn result\n\t\t} catch (err) {\n\t\t\tconst error = err instanceof Error ? err : new Error(String(err))\n\n\t\t\tif (context !== undefined && opts?.onRollback) {\n\t\t\t\tawait opts.onRollback(context, ...args)\n\t\t\t}\n\n\t\t\tif (mountedRef.current) {\n\t\t\t\tsetState({ isLoading: false, error })\n\t\t\t}\n\t\t\topts?.onError?.(error, ...args)\n\t\t\topts?.onSettled?.(undefined, error, ...args)\n\t\t\tthrow error\n\t\t}\n\t}, [])\n\n\tconst mutate = useCallback(\n\t\t(...args: TArgs): void => {\n\t\t\tmutateAsync(...args).catch(() => {\n\t\t\t\t// Fire-and-forget: error is captured in state, no unhandled rejection\n\t\t\t})\n\t\t},\n\t\t[mutateAsync],\n\t)\n\n\tconst reset = useCallback((): void => {\n\t\tif (mountedRef.current) {\n\t\t\tsetState({ isLoading: false, error: null })\n\t\t}\n\t}, [])\n\n\treturn {\n\t\tmutate,\n\t\tmutateAsync,\n\t\tisLoading: state.isLoading,\n\t\terror: state.error,\n\t\treset,\n\t}\n}\n","import type { KoraEventType } from '@korajs/core'\nimport type { SyncStatusInfo } from '@korajs/sync'\nimport { useCallback, useRef, useSyncExternalStore } from 'react'\nimport { useKoraContext } from '../context/kora-context'\n\nconst OFFLINE_STATUS: SyncStatusInfo = Object.freeze({\n\tstatus: 'offline',\n\tpendingOperations: 0,\n\tlastSyncedAt: null,\n\tlastSuccessfulPush: null,\n\tlastSuccessfulPull: null,\n\tconflicts: 0,\n})\n\nconst SYNC_STATUS_EVENT_TYPES = [\n\t'sync:connected',\n\t'sync:disconnected',\n\t'sync:schema-mismatch',\n\t'sync:auth-failed',\n\t'sync:sent',\n\t'sync:received',\n\t'sync:acknowledged',\n\t'sync:apply-failed',\n\t'sync:diagnostics',\n\t'sync:initial-sync-progress',\n] as const satisfies readonly KoraEventType[]\n\n/**\n * React hook for monitoring the sync engine's connection status.\n *\n * Subscribes to sync events via `app.sync.subscribeStatus` (or the sync engine\n * emitter when using store-only mode) and re-renders only when status changes.\n *\n * @returns Current sync status information\n *\n * @example\n * ```typescript\n * const status = useSyncStatus()\n * // status.status: 'connected' | 'syncing' | 'synced' | 'offline' | 'error'\n * ```\n */\nexport function useSyncStatus(): SyncStatusInfo {\n\tconst { syncEngine, subscribeSyncStatus, events } = useKoraContext()\n\tconst snapshotRef = useRef<SyncStatusInfo>(OFFLINE_STATUS)\n\tconst serializedRef = useRef<string>(JSON.stringify(OFFLINE_STATUS))\n\n\tconst subscribe = useCallback(\n\t\t(onStoreChange: () => void): (() => void) => {\n\t\t\tif (subscribeSyncStatus) {\n\t\t\t\treturn subscribeSyncStatus((status) => {\n\t\t\t\t\tsnapshotRef.current = status\n\t\t\t\t\tserializedRef.current = JSON.stringify(status)\n\t\t\t\t\tonStoreChange()\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif (!syncEngine) {\n\t\t\t\treturn () => {}\n\t\t\t}\n\n\t\t\tconst refresh = (): void => {\n\t\t\t\tconst newStatus = syncEngine.getStatus()\n\t\t\t\tconst newSerialized = JSON.stringify(newStatus)\n\t\t\t\tif (newSerialized !== serializedRef.current) {\n\t\t\t\t\tsnapshotRef.current = newStatus\n\t\t\t\t\tserializedRef.current = newSerialized\n\t\t\t\t\tonStoreChange()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (events) {\n\t\t\t\tconst unsubs = SYNC_STATUS_EVENT_TYPES.map((type) => events.on(type, refresh))\n\t\t\t\trefresh()\n\t\t\t\treturn () => {\n\t\t\t\t\tfor (const unsub of unsubs) {\n\t\t\t\t\t\tunsub()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trefresh()\n\t\t\treturn () => {}\n\t\t},\n\t\t[syncEngine, subscribeSyncStatus, events],\n\t)\n\n\tconst getSnapshot = useCallback((): SyncStatusInfo => {\n\t\tif (subscribeSyncStatus) {\n\t\t\treturn snapshotRef.current\n\t\t}\n\t\treturn syncEngine ? syncEngine.getStatus() : OFFLINE_STATUS\n\t}, [syncEngine, subscribeSyncStatus])\n\n\treturn useSyncExternalStore(subscribe, getSnapshot)\n}\n","import type { CollectionAccessor } from '@korajs/store'\nimport { useMemo } from 'react'\nimport { useKoraContext } from '../context/kora-context'\n\n/**\n * React hook that returns a CollectionAccessor for the given collection name.\n * Convenience hook for accessing a collection without going through the store directly.\n *\n * @param name - The collection name (must match a collection in the schema)\n * @returns CollectionAccessor with insert, findById, update, delete, and where methods\n *\n * @example\n * ```typescript\n * const todos = useCollection('todos')\n * await todos.insert({ title: 'New todo' })\n * ```\n */\nexport function useCollection(name: string): CollectionAccessor {\n\tconst { store } = useKoraContext()\n\n\treturn useMemo(() => {\n\t\treturn store.collection(name)\n\t}, [store, name])\n}\n","import type { CollectionAccessor } from '@korajs/store'\nimport { encodeRichtext } from '@korajs/store'\nimport type { AwarenessState, AwarenessUser, CursorInfo } from '@korajs/sync'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport * as Y from 'yjs'\nimport { useKoraContext } from '../context/kora-context'\nimport type { UseRichTextResult } from '../types'\n\nconst LOAD_ORIGIN = 'kora-load'\nconst REMOTE_ORIGIN = 'kora-remote'\nconst DOC_CHANNEL_ORIGIN = 'kora-doc-channel'\nconst TEXT_KEY = 'content'\nconst COMPACT_AFTER_DELTAS = 20\nconst PERSIST_DEBOUNCE_MS = 400\n\nexport interface UseRichTextOptions {\n\t/** Presence identity broadcast with cursor updates. */\n\tuser?: AwarenessUser\n\t/**\n\t * Use the incremental Yjs doc channel for live edits (recommended for large documents).\n\t * When omitted, the channel activates automatically once the snapshot exceeds the sync threshold.\n\t */\n\tuseDocChannel?: boolean\n}\n\n/**\n * Binds a richtext field to a shared Yjs document for editor integration.\n */\nexport function useRichText(\n\tcollectionName: string,\n\trecordId: string,\n\tfieldName: string,\n\toptions?: UseRichTextOptions,\n): UseRichTextResult {\n\tconst { store, syncEngine } = useKoraContext()\n\tconst collection = useMemo<CollectionAccessor>(\n\t\t() => store.collection(collectionName),\n\t\t[store, collectionName],\n\t)\n\tconst [doc] = useState(() => new Y.Doc())\n\tconst [ready, setReady] = useState(false)\n\tconst [error, setError] = useState<Error | null>(null)\n\tconst [canUndo, setCanUndo] = useState(false)\n\tconst [canRedo, setCanRedo] = useState(false)\n\tconst [cursors, setCursors] = useState<CursorInfo[]>([])\n\tconst baseUpdateRef = useRef<Uint8Array | null>(null)\n\tconst pendingDeltasRef = useRef<Uint8Array[]>([])\n\tconst docChannelActiveRef = useRef(false)\n\tconst persistTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\tconst userRef = useRef<AwarenessUser | undefined>(options?.user)\n\n\tuseEffect(() => {\n\t\tuserRef.current = options?.user\n\t}, [options?.user])\n\n\tconst text = useMemo(() => doc.getText(TEXT_KEY), [doc])\n\tconst undoManager = useMemo(() => new Y.UndoManager(text), [text])\n\n\tconst syncHistoryState = useCallback(() => {\n\t\tsetCanUndo(undoManager.undoStack.length > 0)\n\t\tsetCanRedo(undoManager.redoStack.length > 0)\n\t}, [undoManager])\n\n\tconst undo = useCallback(() => {\n\t\tundoManager.undo()\n\t\tsyncHistoryState()\n\t}, [syncHistoryState, undoManager])\n\n\tconst redo = useCallback(() => {\n\t\tundoManager.redo()\n\t\tsyncHistoryState()\n\t}, [syncHistoryState, undoManager])\n\n\tconst resolveAwarenessUser = useCallback((): AwarenessUser => {\n\t\tif (userRef.current) {\n\t\t\treturn userRef.current\n\t\t}\n\t\tif (syncEngine) {\n\t\t\tconst existing = syncEngine.getAwarenessManager().getLocalState()?.user\n\t\t\tif (existing) {\n\t\t\t\treturn existing\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tname: 'Anonymous',\n\t\t\tcolor: '#6366f1',\n\t\t}\n\t}, [syncEngine])\n\n\tconst setCursor = useCallback(\n\t\t(anchor: number, head: number) => {\n\t\t\tif (!syncEngine) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst awareness = syncEngine.getAwarenessManager()\n\t\t\tconst state: AwarenessState = {\n\t\t\t\tuser: resolveAwarenessUser(),\n\t\t\t\tcursor: {\n\t\t\t\t\tcollection: collectionName,\n\t\t\t\t\trecordId,\n\t\t\t\t\tfield: fieldName,\n\t\t\t\t\tanchor,\n\t\t\t\t\thead,\n\t\t\t\t},\n\t\t\t}\n\t\t\tawareness.setLocalState(state)\n\t\t},\n\t\t[collectionName, fieldName, recordId, resolveAwarenessUser, syncEngine],\n\t)\n\n\tconst clearCursor = useCallback(() => {\n\t\tif (!syncEngine) {\n\t\t\treturn\n\t\t}\n\n\t\tconst awareness = syncEngine.getAwarenessManager()\n\t\tconst current = awareness.getLocalState()\n\t\tif (!current?.cursor) {\n\t\t\treturn\n\t\t}\n\t\tif (\n\t\t\tcurrent.cursor.collection !== collectionName ||\n\t\t\tcurrent.cursor.recordId !== recordId ||\n\t\t\tcurrent.cursor.field !== fieldName\n\t\t) {\n\t\t\treturn\n\t\t}\n\n\t\tawareness.setLocalState({ user: current.user })\n\t}, [collectionName, fieldName, recordId, syncEngine])\n\n\tconst applyRemoteSnapshot = useCallback(\n\t\t(value: unknown) => {\n\t\t\tconst encoded = encodeRichtextInput(value)\n\t\t\tif (!encoded) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst currentSnapshot = Y.encodeStateAsUpdate(doc)\n\t\t\tif (updatesEqual(currentSnapshot, encoded)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tY.applyUpdate(doc, encoded, REMOTE_ORIGIN)\n\t\t\tbaseUpdateRef.current = encoded\n\t\t\tpendingDeltasRef.current = []\n\t\t\tsyncHistoryState()\n\t\t},\n\t\t[doc, syncHistoryState],\n\t)\n\n\tuseEffect(() => {\n\t\tlet disposed = false\n\n\t\tconst initialize = async (): Promise<void> => {\n\t\t\tsetReady(false)\n\t\t\tsetError(null)\n\n\t\t\ttry {\n\t\t\t\tconst record = await collection.findById(recordId)\n\t\t\t\tif (disposed) return\n\n\t\t\t\tdoc.transact(() => {\n\t\t\t\t\tconst target = doc.getText(TEXT_KEY)\n\t\t\t\t\ttarget.delete(0, target.length)\n\t\t\t\t}, LOAD_ORIGIN)\n\n\t\t\t\tconst encoded = encodeRichtextInput(record?.[fieldName])\n\t\t\t\tbaseUpdateRef.current = encoded\n\t\t\t\tpendingDeltasRef.current = []\n\t\t\t\tif (encoded) {\n\t\t\t\t\tY.applyUpdate(doc, encoded, LOAD_ORIGIN)\n\t\t\t\t}\n\n\t\t\t\tconst channel = syncEngine?.getRichtextDocChannel?.()\n\t\t\t\tdocChannelActiveRef.current =\n\t\t\t\t\tchannel?.shouldUseChannel(encoded?.length ?? 0, options?.useDocChannel) ?? false\n\n\t\t\t\tsetReady(true)\n\t\t\t} catch (cause) {\n\t\t\t\tif (disposed) return\n\t\t\t\tsetError(cause instanceof Error ? cause : new Error(String(cause)))\n\t\t\t}\n\t\t}\n\n\t\tconst flushPersist = async (): Promise<void> => {\n\t\t\tconst snapshot = composeRichtextSnapshot(baseUpdateRef.current, pendingDeltasRef.current)\n\t\t\tif (pendingDeltasRef.current.length >= COMPACT_AFTER_DELTAS) {\n\t\t\t\tbaseUpdateRef.current = snapshot\n\t\t\t\tpendingDeltasRef.current = []\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait collection.update(recordId, {\n\t\t\t\t\t[fieldName]: snapshot,\n\t\t\t\t})\n\t\t\t} catch (cause) {\n\t\t\t\tif (!disposed) {\n\t\t\t\t\tsetError(cause instanceof Error ? cause : new Error(String(cause)))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst schedulePersist = (): void => {\n\t\t\tif (persistTimerRef.current) {\n\t\t\t\tclearTimeout(persistTimerRef.current)\n\t\t\t}\n\t\t\tpersistTimerRef.current = setTimeout(() => {\n\t\t\t\tpersistTimerRef.current = null\n\t\t\t\tvoid flushPersist()\n\t\t\t}, PERSIST_DEBOUNCE_MS)\n\t\t}\n\n\t\tconst persist = (_update: Uint8Array, origin: unknown): void => {\n\t\t\tsyncHistoryState()\n\t\t\tif (origin === LOAD_ORIGIN || origin === REMOTE_ORIGIN || origin === DOC_CHANNEL_ORIGIN) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tpendingDeltasRef.current.push(_update)\n\n\t\t\tif (docChannelActiveRef.current && syncEngine) {\n\t\t\t\tsyncEngine.getRichtextDocChannel().send(collectionName, recordId, fieldName, _update)\n\t\t\t\tschedulePersist()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tvoid flushPersist()\n\t\t}\n\n\t\tdoc.on('update', persist)\n\t\tvoid initialize()\n\n\t\tsyncHistoryState()\n\n\t\treturn () => {\n\t\t\tdisposed = true\n\t\t\tif (persistTimerRef.current) {\n\t\t\t\tclearTimeout(persistTimerRef.current)\n\t\t\t\tpersistTimerRef.current = null\n\t\t\t}\n\t\t\tdoc.off('update', persist)\n\t\t\tundoManager.destroy()\n\t\t\tbaseUpdateRef.current = null\n\t\t\tpendingDeltasRef.current = []\n\t\t\tdocChannelActiveRef.current = false\n\t\t}\n\t}, [\n\t\tcollection,\n\t\tcollectionName,\n\t\tdoc,\n\t\tfieldName,\n\t\toptions?.useDocChannel,\n\t\trecordId,\n\t\tsyncEngine,\n\t\tsyncHistoryState,\n\t\tundoManager,\n\t])\n\n\t// Incremental Yjs updates from the doc channel (large-document side path).\n\tuseEffect(() => {\n\t\tif (!ready || !syncEngine || !docChannelActiveRef.current) {\n\t\t\treturn\n\t\t}\n\n\t\tconst channel = syncEngine.getRichtextDocChannel()\n\t\treturn channel.subscribe(collectionName, recordId, fieldName, (update) => {\n\t\t\tY.applyUpdate(doc, update, DOC_CHANNEL_ORIGIN)\n\t\t\tsyncHistoryState()\n\t\t})\n\t}, [collectionName, doc, fieldName, ready, recordId, syncEngine, syncHistoryState])\n\n\t// Merge remote richtext writes from sync into the live Y.Doc.\n\tuseEffect(() => {\n\t\tif (!ready) {\n\t\t\treturn\n\t\t}\n\n\t\tconst unsubscribe = store\n\t\t\t.collection(collectionName)\n\t\t\t.where({ id: recordId })\n\t\t\t.subscribe((results) => {\n\t\t\t\tconst record = results[0]\n\t\t\t\tif (!record) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tapplyRemoteSnapshot(record[fieldName])\n\t\t\t})\n\n\t\treturn unsubscribe\n\t}, [applyRemoteSnapshot, collectionName, fieldName, ready, recordId, store])\n\n\t// Track remote collaborators' cursors for this specific field.\n\tuseEffect(() => {\n\t\tif (!syncEngine) return\n\n\t\tconst awareness = syncEngine.getAwarenessManager()\n\t\tconst localClientId = awareness.clientId\n\n\t\tconst updateCursors = (): void => {\n\t\t\tconst states = awareness.getStates()\n\t\t\tconst fieldCursors: CursorInfo[] = []\n\n\t\t\tfor (const [clientId, state] of states) {\n\t\t\t\tif (clientId === localClientId) continue\n\t\t\t\tif (!state.cursor) continue\n\t\t\t\tif (\n\t\t\t\t\tstate.cursor.collection !== collectionName ||\n\t\t\t\t\tstate.cursor.recordId !== recordId ||\n\t\t\t\t\tstate.cursor.field !== fieldName\n\t\t\t\t) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfieldCursors.push({\n\t\t\t\t\tclientId,\n\t\t\t\t\tuserName: state.user.name,\n\t\t\t\t\tcolor: state.user.color,\n\t\t\t\t\tanchor: state.cursor.anchor,\n\t\t\t\t\thead: state.cursor.head,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tsetCursors(fieldCursors)\n\t\t}\n\n\t\tconst unsubscribe = awareness.on('change', () => {\n\t\t\tupdateCursors()\n\t\t})\n\n\t\tupdateCursors()\n\n\t\treturn () => {\n\t\t\tunsubscribe()\n\t\t\tclearCursor()\n\t\t}\n\t}, [clearCursor, collectionName, fieldName, recordId, syncEngine])\n\n\treturn { doc, text, undo, redo, canUndo, canRedo, ready, error, cursors, setCursor, clearCursor }\n}\n\nfunction encodeRichtextInput(value: unknown): Uint8Array | null {\n\tif (value === null || value === undefined) {\n\t\treturn null\n\t}\n\n\ttry {\n\t\treturn encodeRichtext(value as Parameters<typeof encodeRichtext>[0])\n\t} catch {\n\t\tif (typeof value === 'string') {\n\t\t\tconst fallbackDoc = new Y.Doc()\n\t\t\tfallbackDoc.getText(TEXT_KEY).insert(0, value)\n\t\t\treturn Y.encodeStateAsUpdate(fallbackDoc)\n\t\t}\n\t\tthrow new Error('Richtext record value must be a string, Uint8Array, ArrayBuffer, or null.')\n\t}\n}\n\nfunction composeRichtextSnapshot(base: Uint8Array | null, deltas: Uint8Array[]): Uint8Array {\n\tconst mergedDoc = new Y.Doc()\n\tif (base) {\n\t\tY.applyUpdate(mergedDoc, base)\n\t}\n\n\tfor (const delta of deltas) {\n\t\tY.applyUpdate(mergedDoc, delta)\n\t}\n\n\treturn Y.encodeStateAsUpdate(mergedDoc)\n}\n\nfunction updatesEqual(left: Uint8Array, right: Uint8Array): boolean {\n\tif (left.length !== right.length) {\n\t\treturn false\n\t}\n\tfor (let index = 0; index < left.length; index++) {\n\t\tif (left[index] !== right[index]) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAA8E;AAI9E,IAAM,kBAAc,4BAAuC,IAAI;AAqB/D,SAAS,aAAa;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAiC;AAChC,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAuB,SAAS,IAAI;AAC9E,QAAM,CAAC,cAAc,eAAe,QAAI,uBAA4B,cAAc,IAAI;AAEtF,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,CAAC,GAAG;AACvC,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAuB,IAAI;AAE7D,8BAAU,MAAM;AACf,QAAI,CAAC,IAAK;AACV,QAAI,YAAY;AAChB,QAAI,MACF,KAAK,MAAM;AACX,UAAI,UAAW;AACf,uBAAiB,IAAI,SAAS,CAAC;AAC/B,sBAAgB,IAAI,cAAc,CAAC;AACnC,eAAS,IAAI;AAAA,IACd,CAAC,EACA,MAAM,CAAC,UAAmB;AAC1B,UAAI,UAAW;AACf,YAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACpE,cAAQ,MAAM,iCAAiC,GAAG;AAClD,mBAAa,GAAG;AAAA,IACjB,CAAC;AACF,WAAO,MAAM;AACZ,kBAAY;AAAA,IACb;AAAA,EACD,GAAG,CAAC,GAAG,CAAC;AAER,MAAI,WAAW;AACd,eAAO;AAAA,MACN;AAAA,MACA,EAAE,OAAO,EAAE,OAAO,OAAO,SAAS,QAAQ,YAAY,YAAY,EAAE;AAAA,UACpE,4BAAc,UAAU,MAAM,6BAA6B;AAAA,MAC3D,UAAU;AAAA,IACX;AAAA,EACD;AAEA,MAAI,CAAC,OAAO;AACX,WAAQ,YAAY;AAAA,EACrB;AAEA,MAAI,CAAC,eAAe;AACnB,UAAM,IAAI;AAAA,MACT;AAAA,IAED;AAAA,EACD;AAEA,QAAM,QAA0B;AAAA,IAC/B,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,KAAK,OAAO;AAAA,IACZ,QAAQ,KAAK,UAAU;AAAA,IACvB,qBAAqB,KAAK,MAAM,mBAAmB;AAAA,EACpD;AACA,aAAO,4BAAc,YAAY,UAAU,EAAE,MAAM,GAAG,QAAQ;AAC/D;AAMA,SAAS,iBAAmC;AAC3C,QAAM,cAAU,yBAAW,WAAW;AACtC,MAAI,YAAY,MAAM;AACrB,UAAM,IAAI;AAAA,MACT;AAAA,IAED;AAAA,EACD;AACA,SAAO;AACR;;;AChFO,SAAS,SAAiD;AAChE,QAAM,EAAE,IAAI,IAAI,eAAe;AAC/B,MAAI,CAAC,KAAK;AACT,UAAM,IAAI;AAAA,MACT;AAAA,IAED;AAAA,EACD;AACA,SAAO;AACR;;;AChCA,IAAAA,gBAAsD;;;ACKtD,IAAM,cAAkC,OAAO,OAAO,CAAC,CAAC;AAcjD,IAAM,aAAN,MAAuC;AAAA,EACrC,WAAyB;AAAA,EACzB,YAAY,oBAAI,IAAgB;AAAA,EAChC,mBAAwC;AAAA,EACxC,SAAS;AAAA,EACA;AAAA,EAEjB,YAAY,cAA+B;AAC1C,SAAK,eAAe;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,YAAY,CAAC,kBAA4C;AACxD,SAAK,UAAU,IAAI,aAAa;AAGhC,QAAI,CAAC,KAAK,QAAQ;AACjB,WAAK,kBAAkB;AAAA,IACxB;AAEA,WAAO,MAAM;AACZ,WAAK,UAAU,OAAO,aAAa;AAGnC,UAAI,KAAK,UAAU,SAAS,GAAG;AAC9B,aAAK,iBAAiB;AAAA,MACvB;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,MAAoB;AACjC,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAgB;AACf,SAAK,iBAAiB;AACtB,SAAK,UAAU,MAAM;AACrB,SAAK,WAAW;AAAA,EACjB;AAAA,EAEQ,oBAA0B;AACjC,SAAK,SAAS;AACd,SAAK,mBAAmB,KAAK,aAAa,UAAU,CAAC,YAAY;AAChE,UAAI,CAAC,KAAK,OAAQ;AAClB,YAAM,cAAc,OAAO,OAAO,CAAC,GAAG,OAAO,CAAC;AAC9C,WAAK,WAAW;AAChB,WAAK,gBAAgB;AAAA,IACtB,CAAC;AAAA,EACF;AAAA,EAEQ,mBAAyB;AAChC,SAAK,SAAS;AACd,QAAI,KAAK,kBAAkB;AAC1B,WAAK,iBAAiB;AACtB,WAAK,mBAAmB;AAAA,IACzB;AAAA,EACD;AAAA,EAEQ,kBAAwB;AAC/B,eAAW,YAAY,KAAK,WAAW;AACtC,eAAS;AAAA,IACV;AAAA,EACD;AACD;;;AD9FA,IAAM,qBAAqB;AAE3B,SAAS,iBAAiB,OAAoC;AAC7D,QAAM,aAAa,MAAM,cAAc;AACvC,MAAI,WAAW,eAAe,eAAe;AAC5C,UAAM,MAAM,IAAI;AAAA,MACf;AAAA,IACD;AACA,QAAI,OAAO;AACX,WAAO,OAAO,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,UAAM;AAAA,EACP;AACD;AAMA,IAAMC,eAAkC,OAAO,OAAO,CAAC,CAAC;AAExD,IAAM,gBAAgB,CAAC,mBAA6C;AACnE,SAAO,MAAM;AAAA,EAAC;AACf;AAsBO,SAAS,SACf,OACA,SACe;AACf,QAAM,UAAU,SAAS,YAAY;AAErC,MAAI,SAAS;AACZ,qBAAiB,KAAK;AAAA,EACvB;AAGA,QAAM,gBAAgB,KAAK,UAAU,MAAM,cAAc,CAAC;AAG1D,QAAM,oBAAgB,sBAA6B,IAAI;AACvD,QAAM,iBAAa,sBAAsB,IAAI;AAG7C,QAAM,iBAAa,uBAAQ,MAAM;AAChC,QAAI,CAAC,SAAS;AAEb,UAAI,cAAc,SAAS;AAC1B,sBAAc,QAAQ,QAAQ;AAC9B,sBAAc,UAAU;AAAA,MACzB;AACA,iBAAW,UAAU;AACrB,aAAO;AAAA,IACR;AAGA,QAAI,WAAW,YAAY,eAAe;AACzC,UAAI,cAAc,SAAS;AAC1B,sBAAc,QAAQ,QAAQ;AAAA,MAC/B;AACA,YAAM,WAAW,IAAI,WAAc,KAAK;AACxC,oBAAc,UAAU;AACxB,iBAAW,UAAU;AACrB,aAAO;AAAA,IACR;AAEA,WAAO,cAAc;AAAA,EACtB,GAAG,CAAC,eAAe,SAAS,KAAK,CAAC;AAOlC,QAAM,sBAAsB,MAAoBA;AAQhD,aAAO;AAAA,IACN,aAAa,WAAW,YAAY;AAAA,IACpC,aAAa,WAAW,cAAc;AAAA,EACvC;AACD;;;AE7GA,IAAAC,gBAAyD;AA0BlD,SAAS,YACf,YACA,SACkC;AAClC,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAsD;AAAA,IAC/E,WAAW;AAAA,IACX,OAAO;AAAA,EACR,CAAC;AAED,QAAM,iBAAa,sBAAO,IAAI;AAC9B,+BAAU,MAAM;AACf,eAAW,UAAU;AACrB,WAAO,MAAM;AACZ,iBAAW,UAAU;AAAA,IACtB;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,QAAM,YAAQ,sBAAO,UAAU;AAC/B,QAAM,UAAU;AAEhB,QAAM,iBAAa,sBAAO,OAAO;AACjC,aAAW,UAAU;AAErB,QAAM,kBAAc,2BAAY,UAAU,SAAgC;AACzE,UAAM,OAAO,WAAW;AACxB,QAAI;AAEJ,QAAI,WAAW,SAAS;AACvB,eAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IAC1C;AAEA,QAAI;AACH,UAAI,MAAM,UAAU;AACnB,kBAAU,MAAM,KAAK,SAAS,GAAG,IAAI;AAAA,MACtC;AAEA,YAAM,SAAS,MAAM,MAAM,QAAQ,GAAG,IAAI;AAE1C,UAAI,WAAW,SAAS;AACvB,iBAAS,EAAE,WAAW,OAAO,OAAO,KAAK,CAAC;AAAA,MAC3C;AACA,YAAM,YAAY,QAAQ,GAAG,IAAI;AACjC,YAAM,YAAY,QAAQ,MAAM,GAAG,IAAI;AACvC,aAAO;AAAA,IACR,SAAS,KAAK;AACb,YAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAEhE,UAAI,YAAY,UAAa,MAAM,YAAY;AAC9C,cAAM,KAAK,WAAW,SAAS,GAAG,IAAI;AAAA,MACvC;AAEA,UAAI,WAAW,SAAS;AACvB,iBAAS,EAAE,WAAW,OAAO,MAAM,CAAC;AAAA,MACrC;AACA,YAAM,UAAU,OAAO,GAAG,IAAI;AAC9B,YAAM,YAAY,QAAW,OAAO,GAAG,IAAI;AAC3C,YAAM;AAAA,IACP;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,QAAM,aAAS;AAAA,IACd,IAAI,SAAsB;AACzB,kBAAY,GAAG,IAAI,EAAE,MAAM,MAAM;AAAA,MAEjC,CAAC;AAAA,IACF;AAAA,IACA,CAAC,WAAW;AAAA,EACb;AAEA,QAAM,YAAQ,2BAAY,MAAY;AACrC,QAAI,WAAW,SAAS;AACvB,eAAS,EAAE,WAAW,OAAO,OAAO,KAAK,CAAC;AAAA,IAC3C;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA,WAAW,MAAM;AAAA,IACjB,OAAO,MAAM;AAAA,IACb;AAAA,EACD;AACD;;;AC1GA,IAAAC,gBAA0D;AAG1D,IAAM,iBAAiC,OAAO,OAAO;AAAA,EACpD,QAAQ;AAAA,EACR,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,WAAW;AACZ,CAAC;AAED,IAAM,0BAA0B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAgBO,SAAS,gBAAgC;AAC/C,QAAM,EAAE,YAAY,qBAAqB,OAAO,IAAI,eAAe;AACnE,QAAM,kBAAc,sBAAuB,cAAc;AACzD,QAAM,oBAAgB,sBAAe,KAAK,UAAU,cAAc,CAAC;AAEnE,QAAM,gBAAY;AAAA,IACjB,CAAC,kBAA4C;AAC5C,UAAI,qBAAqB;AACxB,eAAO,oBAAoB,CAAC,WAAW;AACtC,sBAAY,UAAU;AACtB,wBAAc,UAAU,KAAK,UAAU,MAAM;AAC7C,wBAAc;AAAA,QACf,CAAC;AAAA,MACF;AAEA,UAAI,CAAC,YAAY;AAChB,eAAO,MAAM;AAAA,QAAC;AAAA,MACf;AAEA,YAAM,UAAU,MAAY;AAC3B,cAAM,YAAY,WAAW,UAAU;AACvC,cAAM,gBAAgB,KAAK,UAAU,SAAS;AAC9C,YAAI,kBAAkB,cAAc,SAAS;AAC5C,sBAAY,UAAU;AACtB,wBAAc,UAAU;AACxB,wBAAc;AAAA,QACf;AAAA,MACD;AAEA,UAAI,QAAQ;AACX,cAAM,SAAS,wBAAwB,IAAI,CAAC,SAAS,OAAO,GAAG,MAAM,OAAO,CAAC;AAC7E,gBAAQ;AACR,eAAO,MAAM;AACZ,qBAAW,SAAS,QAAQ;AAC3B,kBAAM;AAAA,UACP;AAAA,QACD;AAAA,MACD;AAEA,cAAQ;AACR,aAAO,MAAM;AAAA,MAAC;AAAA,IACf;AAAA,IACA,CAAC,YAAY,qBAAqB,MAAM;AAAA,EACzC;AAEA,QAAM,kBAAc,2BAAY,MAAsB;AACrD,QAAI,qBAAqB;AACxB,aAAO,YAAY;AAAA,IACpB;AACA,WAAO,aAAa,WAAW,UAAU,IAAI;AAAA,EAC9C,GAAG,CAAC,YAAY,mBAAmB,CAAC;AAEpC,aAAO,oCAAqB,WAAW,WAAW;AACnD;;;AC7FA,IAAAC,gBAAwB;AAgBjB,SAAS,cAAc,MAAkC;AAC/D,QAAM,EAAE,MAAM,IAAI,eAAe;AAEjC,aAAO,uBAAQ,MAAM;AACpB,WAAO,MAAM,WAAW,IAAI;AAAA,EAC7B,GAAG,CAAC,OAAO,IAAI,CAAC;AACjB;;;ACtBA,mBAA+B;AAE/B,IAAAC,gBAAkE;AAClE,QAAmB;AAInB,IAAM,cAAc;AACpB,IAAM,gBAAgB;AACtB,IAAM,qBAAqB;AAC3B,IAAM,WAAW;AACjB,IAAM,uBAAuB;AAC7B,IAAM,sBAAsB;AAerB,SAAS,YACf,gBACA,UACA,WACA,SACoB;AACpB,QAAM,EAAE,OAAO,WAAW,IAAI,eAAe;AAC7C,QAAM,iBAAa;AAAA,IAClB,MAAM,MAAM,WAAW,cAAc;AAAA,IACrC,CAAC,OAAO,cAAc;AAAA,EACvB;AACA,QAAM,CAAC,GAAG,QAAI,wBAAS,MAAM,IAAM,MAAI,CAAC;AACxC,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,KAAK;AACxC,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AACrD,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,KAAK;AAC5C,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,KAAK;AAC5C,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAuB,CAAC,CAAC;AACvD,QAAM,oBAAgB,sBAA0B,IAAI;AACpD,QAAM,uBAAmB,sBAAqB,CAAC,CAAC;AAChD,QAAM,0BAAsB,sBAAO,KAAK;AACxC,QAAM,sBAAkB,sBAA6C,IAAI;AACzE,QAAM,cAAU,sBAAkC,SAAS,IAAI;AAE/D,+BAAU,MAAM;AACf,YAAQ,UAAU,SAAS;AAAA,EAC5B,GAAG,CAAC,SAAS,IAAI,CAAC;AAElB,QAAM,WAAO,uBAAQ,MAAM,IAAI,QAAQ,QAAQ,GAAG,CAAC,GAAG,CAAC;AACvD,QAAM,kBAAc,uBAAQ,MAAM,IAAM,cAAY,IAAI,GAAG,CAAC,IAAI,CAAC;AAEjE,QAAM,uBAAmB,2BAAY,MAAM;AAC1C,eAAW,YAAY,UAAU,SAAS,CAAC;AAC3C,eAAW,YAAY,UAAU,SAAS,CAAC;AAAA,EAC5C,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,WAAO,2BAAY,MAAM;AAC9B,gBAAY,KAAK;AACjB,qBAAiB;AAAA,EAClB,GAAG,CAAC,kBAAkB,WAAW,CAAC;AAElC,QAAM,WAAO,2BAAY,MAAM;AAC9B,gBAAY,KAAK;AACjB,qBAAiB;AAAA,EAClB,GAAG,CAAC,kBAAkB,WAAW,CAAC;AAElC,QAAM,2BAAuB,2BAAY,MAAqB;AAC7D,QAAI,QAAQ,SAAS;AACpB,aAAO,QAAQ;AAAA,IAChB;AACA,QAAI,YAAY;AACf,YAAM,WAAW,WAAW,oBAAoB,EAAE,cAAc,GAAG;AACnE,UAAI,UAAU;AACb,eAAO;AAAA,MACR;AAAA,IACD;AACA,WAAO;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,IACR;AAAA,EACD,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,gBAAY;AAAA,IACjB,CAAC,QAAgB,SAAiB;AACjC,UAAI,CAAC,YAAY;AAChB;AAAA,MACD;AAEA,YAAM,YAAY,WAAW,oBAAoB;AACjD,YAAM,QAAwB;AAAA,QAC7B,MAAM,qBAAqB;AAAA,QAC3B,QAAQ;AAAA,UACP,YAAY;AAAA,UACZ;AAAA,UACA,OAAO;AAAA,UACP;AAAA,UACA;AAAA,QACD;AAAA,MACD;AACA,gBAAU,cAAc,KAAK;AAAA,IAC9B;AAAA,IACA,CAAC,gBAAgB,WAAW,UAAU,sBAAsB,UAAU;AAAA,EACvE;AAEA,QAAM,kBAAc,2BAAY,MAAM;AACrC,QAAI,CAAC,YAAY;AAChB;AAAA,IACD;AAEA,UAAM,YAAY,WAAW,oBAAoB;AACjD,UAAM,UAAU,UAAU,cAAc;AACxC,QAAI,CAAC,SAAS,QAAQ;AACrB;AAAA,IACD;AACA,QACC,QAAQ,OAAO,eAAe,kBAC9B,QAAQ,OAAO,aAAa,YAC5B,QAAQ,OAAO,UAAU,WACxB;AACD;AAAA,IACD;AAEA,cAAU,cAAc,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,EAC/C,GAAG,CAAC,gBAAgB,WAAW,UAAU,UAAU,CAAC;AAEpD,QAAM,0BAAsB;AAAA,IAC3B,CAAC,UAAmB;AACnB,YAAM,UAAU,oBAAoB,KAAK;AACzC,UAAI,CAAC,SAAS;AACb;AAAA,MACD;AAEA,YAAM,kBAAoB,sBAAoB,GAAG;AACjD,UAAI,aAAa,iBAAiB,OAAO,GAAG;AAC3C;AAAA,MACD;AAEA,MAAE,cAAY,KAAK,SAAS,aAAa;AACzC,oBAAc,UAAU;AACxB,uBAAiB,UAAU,CAAC;AAC5B,uBAAiB;AAAA,IAClB;AAAA,IACA,CAAC,KAAK,gBAAgB;AAAA,EACvB;AAEA,+BAAU,MAAM;AACf,QAAI,WAAW;AAEf,UAAM,aAAa,YAA2B;AAC7C,eAAS,KAAK;AACd,eAAS,IAAI;AAEb,UAAI;AACH,cAAM,SAAS,MAAM,WAAW,SAAS,QAAQ;AACjD,YAAI,SAAU;AAEd,YAAI,SAAS,MAAM;AAClB,gBAAM,SAAS,IAAI,QAAQ,QAAQ;AACnC,iBAAO,OAAO,GAAG,OAAO,MAAM;AAAA,QAC/B,GAAG,WAAW;AAEd,cAAM,UAAU,oBAAoB,SAAS,SAAS,CAAC;AACvD,sBAAc,UAAU;AACxB,yBAAiB,UAAU,CAAC;AAC5B,YAAI,SAAS;AACZ,UAAE,cAAY,KAAK,SAAS,WAAW;AAAA,QACxC;AAEA,cAAM,UAAU,YAAY,wBAAwB;AACpD,4BAAoB,UACnB,SAAS,iBAAiB,SAAS,UAAU,GAAG,SAAS,aAAa,KAAK;AAE5E,iBAAS,IAAI;AAAA,MACd,SAAS,OAAO;AACf,YAAI,SAAU;AACd,iBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,MACnE;AAAA,IACD;AAEA,UAAM,eAAe,YAA2B;AAC/C,YAAM,WAAW,wBAAwB,cAAc,SAAS,iBAAiB,OAAO;AACxF,UAAI,iBAAiB,QAAQ,UAAU,sBAAsB;AAC5D,sBAAc,UAAU;AACxB,yBAAiB,UAAU,CAAC;AAAA,MAC7B;AAEA,UAAI;AACH,cAAM,WAAW,OAAO,UAAU;AAAA,UACjC,CAAC,SAAS,GAAG;AAAA,QACd,CAAC;AAAA,MACF,SAAS,OAAO;AACf,YAAI,CAAC,UAAU;AACd,mBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,QACnE;AAAA,MACD;AAAA,IACD;AAEA,UAAM,kBAAkB,MAAY;AACnC,UAAI,gBAAgB,SAAS;AAC5B,qBAAa,gBAAgB,OAAO;AAAA,MACrC;AACA,sBAAgB,UAAU,WAAW,MAAM;AAC1C,wBAAgB,UAAU;AAC1B,aAAK,aAAa;AAAA,MACnB,GAAG,mBAAmB;AAAA,IACvB;AAEA,UAAM,UAAU,CAAC,SAAqB,WAA0B;AAC/D,uBAAiB;AACjB,UAAI,WAAW,eAAe,WAAW,iBAAiB,WAAW,oBAAoB;AACxF;AAAA,MACD;AAEA,uBAAiB,QAAQ,KAAK,OAAO;AAErC,UAAI,oBAAoB,WAAW,YAAY;AAC9C,mBAAW,sBAAsB,EAAE,KAAK,gBAAgB,UAAU,WAAW,OAAO;AACpF,wBAAgB;AAChB;AAAA,MACD;AAEA,WAAK,aAAa;AAAA,IACnB;AAEA,QAAI,GAAG,UAAU,OAAO;AACxB,SAAK,WAAW;AAEhB,qBAAiB;AAEjB,WAAO,MAAM;AACZ,iBAAW;AACX,UAAI,gBAAgB,SAAS;AAC5B,qBAAa,gBAAgB,OAAO;AACpC,wBAAgB,UAAU;AAAA,MAC3B;AACA,UAAI,IAAI,UAAU,OAAO;AACzB,kBAAY,QAAQ;AACpB,oBAAc,UAAU;AACxB,uBAAiB,UAAU,CAAC;AAC5B,0BAAoB,UAAU;AAAA,IAC/B;AAAA,EACD,GAAG;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,CAAC;AAGD,+BAAU,MAAM;AACf,QAAI,CAAC,SAAS,CAAC,cAAc,CAAC,oBAAoB,SAAS;AAC1D;AAAA,IACD;AAEA,UAAM,UAAU,WAAW,sBAAsB;AACjD,WAAO,QAAQ,UAAU,gBAAgB,UAAU,WAAW,CAAC,WAAW;AACzE,MAAE,cAAY,KAAK,QAAQ,kBAAkB;AAC7C,uBAAiB;AAAA,IAClB,CAAC;AAAA,EACF,GAAG,CAAC,gBAAgB,KAAK,WAAW,OAAO,UAAU,YAAY,gBAAgB,CAAC;AAGlF,+BAAU,MAAM;AACf,QAAI,CAAC,OAAO;AACX;AAAA,IACD;AAEA,UAAM,cAAc,MAClB,WAAW,cAAc,EACzB,MAAM,EAAE,IAAI,SAAS,CAAC,EACtB,UAAU,CAAC,YAAY;AACvB,YAAM,SAAS,QAAQ,CAAC;AACxB,UAAI,CAAC,QAAQ;AACZ;AAAA,MACD;AACA,0BAAoB,OAAO,SAAS,CAAC;AAAA,IACtC,CAAC;AAEF,WAAO;AAAA,EACR,GAAG,CAAC,qBAAqB,gBAAgB,WAAW,OAAO,UAAU,KAAK,CAAC;AAG3E,+BAAU,MAAM;AACf,QAAI,CAAC,WAAY;AAEjB,UAAM,YAAY,WAAW,oBAAoB;AACjD,UAAM,gBAAgB,UAAU;AAEhC,UAAM,gBAAgB,MAAY;AACjC,YAAM,SAAS,UAAU,UAAU;AACnC,YAAM,eAA6B,CAAC;AAEpC,iBAAW,CAAC,UAAU,KAAK,KAAK,QAAQ;AACvC,YAAI,aAAa,cAAe;AAChC,YAAI,CAAC,MAAM,OAAQ;AACnB,YACC,MAAM,OAAO,eAAe,kBAC5B,MAAM,OAAO,aAAa,YAC1B,MAAM,OAAO,UAAU,WACtB;AACD;AAAA,QACD;AACA,qBAAa,KAAK;AAAA,UACjB;AAAA,UACA,UAAU,MAAM,KAAK;AAAA,UACrB,OAAO,MAAM,KAAK;AAAA,UAClB,QAAQ,MAAM,OAAO;AAAA,UACrB,MAAM,MAAM,OAAO;AAAA,QACpB,CAAC;AAAA,MACF;AAEA,iBAAW,YAAY;AAAA,IACxB;AAEA,UAAM,cAAc,UAAU,GAAG,UAAU,MAAM;AAChD,oBAAc;AAAA,IACf,CAAC;AAED,kBAAc;AAEd,WAAO,MAAM;AACZ,kBAAY;AACZ,kBAAY;AAAA,IACb;AAAA,EACD,GAAG,CAAC,aAAa,gBAAgB,WAAW,UAAU,UAAU,CAAC;AAEjE,SAAO,EAAE,KAAK,MAAM,MAAM,MAAM,SAAS,SAAS,OAAO,OAAO,SAAS,WAAW,YAAY;AACjG;AAEA,SAAS,oBAAoB,OAAmC;AAC/D,MAAI,UAAU,QAAQ,UAAU,QAAW;AAC1C,WAAO;AAAA,EACR;AAEA,MAAI;AACH,eAAO,6BAAe,KAA6C;AAAA,EACpE,QAAQ;AACP,QAAI,OAAO,UAAU,UAAU;AAC9B,YAAM,cAAc,IAAM,MAAI;AAC9B,kBAAY,QAAQ,QAAQ,EAAE,OAAO,GAAG,KAAK;AAC7C,aAAS,sBAAoB,WAAW;AAAA,IACzC;AACA,UAAM,IAAI,MAAM,2EAA2E;AAAA,EAC5F;AACD;AAEA,SAAS,wBAAwB,MAAyB,QAAkC;AAC3F,QAAM,YAAY,IAAM,MAAI;AAC5B,MAAI,MAAM;AACT,IAAE,cAAY,WAAW,IAAI;AAAA,EAC9B;AAEA,aAAW,SAAS,QAAQ;AAC3B,IAAE,cAAY,WAAW,KAAK;AAAA,EAC/B;AAEA,SAAS,sBAAoB,SAAS;AACvC;AAEA,SAAS,aAAa,MAAkB,OAA4B;AACnE,MAAI,KAAK,WAAW,MAAM,QAAQ;AACjC,WAAO;AAAA,EACR;AACA,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AACjD,QAAI,KAAK,KAAK,MAAM,MAAM,KAAK,GAAG;AACjC,aAAO;AAAA,IACR;AAAA,EACD;AACA,SAAO;AACR;","names":["import_react","EMPTY_ARRAY","import_react","import_react","import_react","import_react"]}