@korajs/svelte 0.5.0 → 0.6.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.js CHANGED
@@ -1,7 +1,23 @@
1
- // src/index.ts
1
+ // src/context.ts
2
2
  import { KoraError } from "@korajs/core";
3
+ import { QueryStoreCache } from "@korajs/store";
3
4
  import { getContext, setContext } from "svelte";
5
+ var koraContextKey = /* @__PURE__ */ Symbol("korajs-context");
4
6
  var koraAppContextKey = /* @__PURE__ */ Symbol("korajs-app");
7
+ function setKoraContext(value) {
8
+ setContext(koraContextKey, value);
9
+ }
10
+ function getKoraContext() {
11
+ const context = getContext(koraContextKey);
12
+ if (!context) {
13
+ throw new KoraError(
14
+ "Kora context missing. Wrap your app with <KoraProvider app={kora}> or <KoraStoreProvider store={store}>.",
15
+ "KORA_NOT_PROVIDED",
16
+ { fix: "Wrap your app with <KoraProvider app={kora}> or <KoraStoreProvider store={store}>." }
17
+ );
18
+ }
19
+ return context;
20
+ }
5
21
  function setKoraAppContext(koraApp) {
6
22
  setContext(koraAppContextKey, koraApp);
7
23
  }
@@ -9,17 +25,277 @@ function getKoraApp() {
9
25
  const app = getContext(koraAppContextKey);
10
26
  if (!app) {
11
27
  throw new KoraError(
12
- "getKoraApp() requires setKoraAppContext(koraApp) on an ancestor component.",
13
- "KORA_NOT_PROVIDED",
14
- {
15
- fix: "In +layout.svelte: setKoraAppContext(kora); await kora.ready before queries."
16
- }
28
+ "getKoraApp() requires setKoraAppContext(koraApp) on an ancestor.",
29
+ "KORA_NOT_PROVIDED"
30
+ );
31
+ }
32
+ return app;
33
+ }
34
+ async function initKoraProvider(app) {
35
+ await app.ready;
36
+ const queryStoreCache = typeof app.getQueryStoreCache === "function" ? app.getQueryStoreCache() : new QueryStoreCache();
37
+ const value = {
38
+ store: app.getStore(),
39
+ syncEngine: app.getSyncEngine(),
40
+ app,
41
+ events: app.events ?? null,
42
+ subscribeSyncStatus: app.sync?.subscribeStatus ?? null,
43
+ queryStoreCache
44
+ };
45
+ setKoraContext(value);
46
+ setKoraAppContext(app);
47
+ return value;
48
+ }
49
+
50
+ // src/stores/query-store.ts
51
+ import { assertQueryReady } from "@korajs/store";
52
+ import { readable } from "svelte/store";
53
+ var EMPTY_ARRAY = Object.freeze([]);
54
+ function createQueryStore(query, options) {
55
+ const { queryStoreCache } = getKoraContext();
56
+ const enabled = options?.enabled !== false;
57
+ return readable(EMPTY_ARRAY, (set) => {
58
+ if (!enabled) {
59
+ set(EMPTY_ARRAY);
60
+ return () => {
61
+ };
62
+ }
63
+ assertQueryReady(query);
64
+ const queryStore = queryStoreCache.getOrCreate(query);
65
+ const unsubscribe = queryStore.subscribe(() => {
66
+ set(queryStore.getSnapshot());
67
+ });
68
+ set(queryStore.getSnapshot());
69
+ return () => {
70
+ unsubscribe();
71
+ queryStoreCache.release(query);
72
+ };
73
+ });
74
+ }
75
+ var useQuery = createQueryStore;
76
+
77
+ // src/composables/use-mutation.ts
78
+ import { createMutationController } from "@korajs/core/bindings";
79
+ function createMutation(mutationFn, options) {
80
+ const optionsRef = { current: options };
81
+ optionsRef.current = options;
82
+ const fnRef = { current: mutationFn };
83
+ fnRef.current = mutationFn;
84
+ const controller = createMutationController({
85
+ mutationFn: (...args) => fnRef.current(...args),
86
+ resolveOptions: () => optionsRef.current
87
+ });
88
+ const loadingListeners = /* @__PURE__ */ new Set();
89
+ const errorListeners = /* @__PURE__ */ new Set();
90
+ controller.subscribe(() => {
91
+ const snapshot = controller.getSnapshot();
92
+ for (const listener of loadingListeners) {
93
+ listener(snapshot.isLoading);
94
+ }
95
+ for (const listener of errorListeners) {
96
+ listener(snapshot.error);
97
+ }
98
+ });
99
+ return {
100
+ mutate: (...args) => controller.mutate(...args),
101
+ mutateAsync: (...args) => controller.mutateAsync(...args),
102
+ subscribeLoading: (fn) => {
103
+ loadingListeners.add(fn);
104
+ fn(controller.getSnapshot().isLoading);
105
+ return () => loadingListeners.delete(fn);
106
+ },
107
+ subscribeError: (fn) => {
108
+ errorListeners.add(fn);
109
+ fn(controller.getSnapshot().error);
110
+ return () => errorListeners.delete(fn);
111
+ },
112
+ get loading() {
113
+ return controller.getSnapshot().isLoading;
114
+ },
115
+ get isLoading() {
116
+ return controller.getSnapshot().isLoading;
117
+ },
118
+ get error() {
119
+ return controller.getSnapshot().error;
120
+ },
121
+ reset: () => controller.reset()
122
+ };
123
+ }
124
+ var useMutation = createMutation;
125
+
126
+ // src/composables/use-sync-status.ts
127
+ import { OFFLINE_SYNC_STATUS, createSyncStatusController } from "@korajs/sync";
128
+ import { readable as readable2 } from "svelte/store";
129
+ function createSyncStatusStore() {
130
+ const { syncEngine, subscribeSyncStatus, events } = getKoraContext();
131
+ return readable2(OFFLINE_SYNC_STATUS, (set) => {
132
+ const controller = createSyncStatusController({
133
+ syncEngine,
134
+ subscribeSyncStatus,
135
+ events: subscribeSyncStatus ? null : events
136
+ });
137
+ set(controller.getSnapshot());
138
+ const unsubscribe = controller.subscribe(() => {
139
+ set(controller.getSnapshot());
140
+ });
141
+ return () => {
142
+ unsubscribe();
143
+ controller.destroy();
144
+ };
145
+ });
146
+ }
147
+ var useSyncStatus = createSyncStatusStore;
148
+
149
+ // src/composables/use-app.ts
150
+ function getApp() {
151
+ const { app } = getKoraContext();
152
+ if (!app) {
153
+ throw new Error(
154
+ "getApp() requires <KoraProvider app={kora}> or <KoraStoreProvider store={store}> with a createApp() instance."
17
155
  );
18
156
  }
19
157
  return app;
20
158
  }
159
+ var useApp = getApp;
160
+
161
+ // src/composables/use-collection.ts
162
+ function getCollection(name) {
163
+ const { store } = getKoraContext();
164
+ return store.collection(name);
165
+ }
166
+ var useCollection = getCollection;
167
+
168
+ // src/composables/use-rich-text.ts
169
+ import { asRichTextSyncEngine, createRichTextController } from "@korajs/store";
170
+ import { onDestroy } from "svelte";
171
+ import { get, readable as readable3 } from "svelte/store";
172
+ function createRichTextBinding(collectionName, recordId, fieldName, options) {
173
+ const { store, syncEngine } = getKoraContext();
174
+ const controller = createRichTextController({
175
+ collection: store.collection(collectionName),
176
+ collectionName,
177
+ recordId,
178
+ fieldName,
179
+ store,
180
+ syncEngine: asRichTextSyncEngine(syncEngine),
181
+ useDocChannel: options?.useDocChannel,
182
+ user: options?.user
183
+ });
184
+ onDestroy(() => {
185
+ controller.destroy();
186
+ });
187
+ const resultStore = readable3(buildResult(controller), (set) => {
188
+ const sync = () => {
189
+ set(buildResult(controller));
190
+ };
191
+ sync();
192
+ return controller.subscribe(sync);
193
+ });
194
+ return {
195
+ get doc() {
196
+ return controller.doc;
197
+ },
198
+ get text() {
199
+ return controller.text;
200
+ },
201
+ undo: () => controller.undo(),
202
+ redo: () => controller.redo(),
203
+ get ready() {
204
+ return get(resultStore).ready;
205
+ },
206
+ get error() {
207
+ return get(resultStore).error;
208
+ },
209
+ get canUndo() {
210
+ return get(resultStore).canUndo;
211
+ },
212
+ get canRedo() {
213
+ return get(resultStore).canRedo;
214
+ },
215
+ get cursors() {
216
+ return get(resultStore).cursors;
217
+ },
218
+ setCursor: (anchor, head) => controller.setCursor(anchor, head),
219
+ clearCursor: () => controller.clearCursor(),
220
+ subscribe: resultStore.subscribe
221
+ };
222
+ }
223
+ var useRichText = createRichTextBinding;
224
+ function buildResult(controller) {
225
+ const snapshot = controller.getSnapshot();
226
+ return {
227
+ doc: controller.doc,
228
+ text: controller.text,
229
+ undo: () => controller.undo(),
230
+ redo: () => controller.redo(),
231
+ ready: snapshot.ready,
232
+ error: snapshot.error,
233
+ canUndo: snapshot.canUndo,
234
+ canRedo: snapshot.canRedo,
235
+ cursors: [...snapshot.cursors],
236
+ setCursor: (anchor, head) => controller.setCursor(anchor, head),
237
+ clearCursor: () => controller.clearCursor()
238
+ };
239
+ }
240
+
241
+ // src/composables/use-presence.ts
242
+ function applyPresence(user) {
243
+ const { syncEngine } = getKoraContext();
244
+ if (!syncEngine || !user?.name || !user?.color) {
245
+ return () => {
246
+ };
247
+ }
248
+ const awareness = syncEngine.getAwarenessManager();
249
+ awareness.setLocalState({
250
+ user: {
251
+ name: user.name,
252
+ color: user.color,
253
+ avatar: user.avatar
254
+ }
255
+ });
256
+ return () => {
257
+ awareness.setLocalState(null);
258
+ };
259
+ }
260
+ var usePresence = applyPresence;
261
+
262
+ // src/composables/use-collaborators.ts
263
+ import { subscribeRemoteAwarenessStates } from "@korajs/sync";
264
+ import { readable as readable4 } from "svelte/store";
265
+ function createCollaboratorsStore() {
266
+ const { syncEngine } = getKoraContext();
267
+ return readable4([], (set) => {
268
+ if (!syncEngine) {
269
+ set([]);
270
+ return () => {
271
+ };
272
+ }
273
+ const awareness = syncEngine.getAwarenessManager();
274
+ return subscribeRemoteAwarenessStates(awareness, set);
275
+ });
276
+ }
277
+ var useCollaborators = createCollaboratorsStore;
21
278
  export {
279
+ applyPresence,
280
+ createCollaboratorsStore,
281
+ createMutation,
282
+ createQueryStore,
283
+ createRichTextBinding,
284
+ createSyncStatusStore,
285
+ getApp,
286
+ getCollection,
22
287
  getKoraApp,
23
- setKoraAppContext
288
+ getKoraContext,
289
+ initKoraProvider,
290
+ setKoraAppContext,
291
+ setKoraContext,
292
+ useApp,
293
+ useCollaborators,
294
+ useCollection,
295
+ useMutation,
296
+ usePresence,
297
+ useQuery,
298
+ useRichText,
299
+ useSyncStatus
24
300
  };
25
301
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { KoraError } from '@korajs/core'\nimport { getContext, setContext } from 'svelte'\nimport type { KoraAppHandle } from './types'\n\nexport type { KoraAppHandle } from './types'\n\nconst koraAppContextKey = Symbol('korajs-app')\n\n/**\n * Set the Kora app in Svelte context (call from a root layout or `+layout.svelte`).\n */\nexport function setKoraAppContext(koraApp: KoraAppHandle): void {\n\tsetContext(koraAppContextKey, koraApp)\n}\n\n/**\n * Read the Kora app from Svelte context in child components.\n */\nexport function getKoraApp(): KoraAppHandle {\n\tconst app = getContext<KoraAppHandle | undefined>(koraAppContextKey)\n\tif (!app) {\n\t\tthrow new KoraError(\n\t\t\t'getKoraApp() requires setKoraAppContext(koraApp) on an ancestor component.',\n\t\t\t'KORA_NOT_PROVIDED',\n\t\t\t{\n\t\t\t\tfix: 'In +layout.svelte: setKoraAppContext(kora); await kora.ready before queries.',\n\t\t\t},\n\t\t)\n\t}\n\treturn app\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,YAAY,kBAAkB;AAKvC,IAAM,oBAAoB,uBAAO,YAAY;AAKtC,SAAS,kBAAkB,SAA8B;AAC/D,aAAW,mBAAmB,OAAO;AACtC;AAKO,SAAS,aAA4B;AAC3C,QAAM,MAAM,WAAsC,iBAAiB;AACnE,MAAI,CAAC,KAAK;AACT,UAAM,IAAI;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,QACC,KAAK;AAAA,MACN;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;","names":[]}
1
+ {"version":3,"sources":["../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":["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'\n\t\t\t? app.getQueryStoreCache()\n\t\t\t: 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 { readable, type 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 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\tcontroller.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\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 { readable, type 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 { get, readable, type 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(\n\tcontroller: ReturnType<typeof createRichTextController>,\n): 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 { readable, type 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":["readable","readable","readable","readable","readable","readable"]}
package/package.json CHANGED
@@ -1,44 +1,74 @@
1
1
  {
2
2
  "name": "@korajs/svelte",
3
- "version": "0.5.0",
4
- "description": "Experimental Svelte bindings stub for Kora.js (context helpers)",
3
+ "version": "0.6.0",
4
+ "description": "Kora.js Svelte bindings for offline-first applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",
9
+ "svelte": "./dist/index.js",
9
10
  "exports": {
10
11
  ".": {
11
- "import": {
12
- "types": "./dist/index.d.ts",
13
- "default": "./dist/index.js"
14
- },
15
- "require": {
16
- "types": "./dist/index.d.cts",
17
- "default": "./dist/index.cjs"
18
- }
12
+ "types": "./dist/index.d.ts",
13
+ "svelte": "./dist/index.js",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ },
17
+ "./KoraQuery.svelte": {
18
+ "svelte": "./src/components/KoraQuery.svelte",
19
+ "import": "./dist/components/KoraQuery.js",
20
+ "default": "./dist/components/KoraQuery.js"
21
+ },
22
+ "./KoraRichText.svelte": {
23
+ "svelte": "./src/components/KoraRichText.svelte",
24
+ "import": "./dist/components/KoraRichText.js",
25
+ "default": "./dist/components/KoraRichText.js"
26
+ },
27
+ "./KoraProvider.svelte": {
28
+ "svelte": "./src/components/KoraProvider.svelte",
29
+ "import": "./dist/components/KoraProvider.js",
30
+ "default": "./dist/components/KoraProvider.js"
31
+ },
32
+ "./KoraStoreProvider.svelte": {
33
+ "svelte": "./src/components/KoraStoreProvider.svelte",
34
+ "import": "./dist/components/KoraStoreProvider.js",
35
+ "default": "./dist/components/KoraStoreProvider.js"
19
36
  }
20
37
  },
21
38
  "files": [
22
- "dist"
39
+ "dist",
40
+ "src/components/KoraQuery.svelte",
41
+ "src/components/KoraRichText.svelte",
42
+ "src/components/KoraProvider.svelte",
43
+ "src/components/KoraStoreProvider.svelte"
23
44
  ],
24
45
  "peerDependencies": {
25
46
  "svelte": "^4.0.0 || ^5.0.0"
26
47
  },
27
48
  "dependencies": {
28
- "@korajs/store": "0.5.0",
29
- "@korajs/core": "0.5.0"
49
+ "yjs": "^13.6.30",
50
+ "@korajs/core": "0.6.0",
51
+ "@korajs/store": "0.6.0",
52
+ "@korajs/sync": "0.6.0"
30
53
  },
31
54
  "devDependencies": {
55
+ "@sveltejs/vite-plugin-svelte": "^5.0.3",
56
+ "@testing-library/svelte": "^5.2.6",
57
+ "@testing-library/user-event": "^14.6.1",
58
+ "happy-dom": "^17.4.4",
59
+ "svelte": "^5.0.0",
32
60
  "tsup": "^8.3.6",
33
61
  "typescript": "^5.7.3",
34
- "svelte": "^5.0.0"
62
+ "vitest": "^3.0.4"
35
63
  },
36
64
  "license": "MIT",
37
65
  "scripts": {
38
- "build": "tsup",
66
+ "build": "tsup && node scripts/build-components.mjs",
39
67
  "dev": "tsup --watch",
68
+ "test": "vitest run",
69
+ "test:watch": "vitest",
40
70
  "typecheck": "tsc --noEmit",
41
71
  "lint": "biome check src/",
42
- "clean": "rm -rf dist .turbo"
72
+ "clean": "rm -rf dist .turbo coverage"
43
73
  }
44
74
  }
@@ -0,0 +1,54 @@
1
+ <script lang="ts">
2
+ import type { KoraAppLike } from '../types'
3
+ import KoraContextBridge from './KoraContextBridge.svelte'
4
+ import KoraStoreBridge from './KoraStoreBridge.svelte'
5
+
6
+ interface Props {
7
+ app: KoraAppLike
8
+ fallback?: import('svelte').Snippet
9
+ children?: import('svelte').Snippet
10
+ }
11
+
12
+ let { app, fallback, children }: Props = $props()
13
+
14
+ let ready = $state(false)
15
+ let initError = $state<Error | null>(null)
16
+
17
+ $effect(() => {
18
+ let cancelled = false
19
+ ready = false
20
+ initError = null
21
+
22
+ void (async () => {
23
+ try {
24
+ await app.ready
25
+ if (cancelled) return
26
+ ready = true
27
+ } catch (error: unknown) {
28
+ if (cancelled) return
29
+ initError = error instanceof Error ? error : new Error(String(error))
30
+ console.error('[Kora] Initialization failed:', initError)
31
+ }
32
+ })()
33
+
34
+ return () => {
35
+ cancelled = true
36
+ }
37
+ })
38
+ </script>
39
+
40
+ {#if initError}
41
+ <div role="alert" style="color: red; padding: 1rem; font-family: monospace;">
42
+ <strong>Kora initialization error: </strong>{initError.message}
43
+ </div>
44
+ {:else if !ready}
45
+ {#if fallback}
46
+ {@render fallback()}
47
+ {:else}
48
+ <div>Loading...</div>
49
+ {/if}
50
+ {:else if children}
51
+ <KoraContextBridge {app}>
52
+ {@render children()}
53
+ </KoraContextBridge>
54
+ {/if}
@@ -0,0 +1,44 @@
1
+ <script lang="ts" module>
2
+ import type { CollectionRecord, QueryBuilder } from '@korajs/store'
3
+ </script>
4
+
5
+ <script lang="ts" generics="T extends CollectionRecord = CollectionRecord">
6
+ import { assertQueryReady } from '@korajs/store'
7
+ import { getKoraContext } from '../context'
8
+
9
+ interface Props {
10
+ query: QueryBuilder<T>
11
+ enabled?: boolean
12
+ children?: import('svelte').Snippet<[readonly T[]]>
13
+ }
14
+
15
+ let { query, enabled = true, children }: Props = $props()
16
+
17
+ getKoraContext()
18
+
19
+ let data = $state<readonly T[]>([])
20
+
21
+ $effect(() => {
22
+ if (!enabled) {
23
+ data = []
24
+ return
25
+ }
26
+
27
+ const { queryStoreCache } = getKoraContext()
28
+ assertQueryReady(query as QueryBuilder<unknown>)
29
+ const queryStore = queryStoreCache.getOrCreate(query)
30
+ const unsubscribe = queryStore.subscribe(() => {
31
+ data = queryStore.getSnapshot()
32
+ })
33
+ data = queryStore.getSnapshot()
34
+
35
+ return () => {
36
+ unsubscribe()
37
+ queryStoreCache.release(query as QueryBuilder<unknown>)
38
+ }
39
+ })
40
+ </script>
41
+
42
+ {#if children}
43
+ {@render children(data)}
44
+ {/if}
@@ -0,0 +1,63 @@
1
+ <script lang="ts">
2
+ import { asRichTextSyncEngine, createRichTextController } from '@korajs/store'
3
+ import type { AwarenessUser } from '@korajs/sync'
4
+ import { getKoraContext } from '../context'
5
+ import type { UseRichTextResult } from '../types'
6
+
7
+ interface Props {
8
+ collectionName: string
9
+ recordId: string
10
+ fieldName: string
11
+ user?: AwarenessUser
12
+ useDocChannel?: boolean
13
+ children?: import('svelte').Snippet<[UseRichTextResult]>
14
+ }
15
+
16
+ let { collectionName, recordId, fieldName, user, useDocChannel, children }: Props = $props()
17
+
18
+ const { store, syncEngine } = getKoraContext()
19
+ let result = $state<UseRichTextResult | null>(null)
20
+
21
+ $effect(() => {
22
+ const controller = createRichTextController({
23
+ collection: store.collection(collectionName),
24
+ collectionName,
25
+ recordId,
26
+ fieldName,
27
+ store,
28
+ syncEngine: asRichTextSyncEngine(syncEngine),
29
+ useDocChannel,
30
+ user,
31
+ })
32
+
33
+ const sync = (): void => {
34
+ const snapshot = controller.getSnapshot()
35
+ result = {
36
+ doc: controller.doc,
37
+ text: controller.text,
38
+ undo: () => controller.undo(),
39
+ redo: () => controller.redo(),
40
+ ready: snapshot.ready,
41
+ error: snapshot.error,
42
+ canUndo: snapshot.canUndo,
43
+ canRedo: snapshot.canRedo,
44
+ cursors: [...snapshot.cursors],
45
+ setCursor: (anchor, head) => controller.setCursor(anchor, head),
46
+ clearCursor: () => controller.clearCursor(),
47
+ }
48
+ }
49
+
50
+ sync()
51
+ const unsubscribe = controller.subscribe(sync)
52
+
53
+ return () => {
54
+ unsubscribe()
55
+ controller.destroy()
56
+ result = null
57
+ }
58
+ })
59
+ </script>
60
+
61
+ {#if result && children}
62
+ {@render children(result)}
63
+ {/if}
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import type { KoraContextValue } from '../types'
3
+ import KoraStoreBridge from './KoraStoreBridge.svelte'
4
+
5
+ interface Props {
6
+ store: KoraContextValue['store']
7
+ syncEngine?: KoraContextValue['syncEngine']
8
+ children?: import('svelte').Snippet
9
+ }
10
+
11
+ let { store, syncEngine = null, children }: Props = $props()
12
+ </script>
13
+
14
+ <KoraStoreBridge {store} {syncEngine}>
15
+ {#if children}
16
+ {@render children()}
17
+ {/if}
18
+ </KoraStoreBridge>