@korajs/react 0.0.0-canary-20261008174129
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/LICENSE +21 -0
- package/README.md +78 -0
- package/dist/index.cjs +626 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +322 -0
- package/dist/index.d.ts +322 -0
- package/dist/index.js +595 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AuthBoundKoraProvider: () => AuthBoundKoraProvider,
|
|
24
|
+
KoraProvider: () => KoraProvider,
|
|
25
|
+
classifyKoraInitializationError: () => classifyKoraInitializationError,
|
|
26
|
+
createKoraHooks: () => createKoraHooks,
|
|
27
|
+
useApp: () => useApp,
|
|
28
|
+
useCollaborators: () => useCollaborators,
|
|
29
|
+
useCollection: () => useCollection,
|
|
30
|
+
useMutation: () => useMutation,
|
|
31
|
+
usePresence: () => usePresence,
|
|
32
|
+
useQuery: () => useQuery,
|
|
33
|
+
useQueryState: () => useQueryState,
|
|
34
|
+
useRichText: () => useRichText,
|
|
35
|
+
useSyncStatus: () => useSyncStatus
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(index_exports);
|
|
38
|
+
|
|
39
|
+
// src/context/kora-context.ts
|
|
40
|
+
var import_store = require("@korajs/store");
|
|
41
|
+
var import_react = require("react");
|
|
42
|
+
var KoraContext = (0, import_react.createContext)(null);
|
|
43
|
+
function KoraProvider({
|
|
44
|
+
app,
|
|
45
|
+
store,
|
|
46
|
+
syncEngine,
|
|
47
|
+
fallback,
|
|
48
|
+
children
|
|
49
|
+
}) {
|
|
50
|
+
const [resolvedStore, setResolvedStore] = (0, import_react.useState)(store ?? null);
|
|
51
|
+
const [resolvedSync, setResolvedSync] = (0, import_react.useState)(syncEngine ?? null);
|
|
52
|
+
const [ready, setReady] = (0, import_react.useState)(!app);
|
|
53
|
+
const [initError, setInitError] = (0, import_react.useState)(null);
|
|
54
|
+
const fallbackQueryStoreCache = (0, import_react.useRef)(null);
|
|
55
|
+
if (!fallbackQueryStoreCache.current) {
|
|
56
|
+
fallbackQueryStoreCache.current = new import_store.QueryStoreCache();
|
|
57
|
+
}
|
|
58
|
+
(0, import_react.useEffect)(() => {
|
|
59
|
+
if (!app) return;
|
|
60
|
+
let cancelled = false;
|
|
61
|
+
app.ready.then(() => {
|
|
62
|
+
if (cancelled) return;
|
|
63
|
+
setResolvedStore(app.getStore());
|
|
64
|
+
setResolvedSync(app.getSyncEngine());
|
|
65
|
+
setReady(true);
|
|
66
|
+
}).catch((error) => {
|
|
67
|
+
if (cancelled) return;
|
|
68
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
69
|
+
console.error("[Kora] Initialization failed:", err);
|
|
70
|
+
setInitError(err);
|
|
71
|
+
});
|
|
72
|
+
return () => {
|
|
73
|
+
cancelled = true;
|
|
74
|
+
};
|
|
75
|
+
}, [app]);
|
|
76
|
+
(0, import_react.useEffect)(() => {
|
|
77
|
+
return () => {
|
|
78
|
+
if (!app) {
|
|
79
|
+
fallbackQueryStoreCache.current?.clear();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}, [app]);
|
|
83
|
+
const contextValue = (0, import_react.useMemo)(() => {
|
|
84
|
+
if (!resolvedStore) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
if (fallbackQueryStoreCache.current === null) {
|
|
88
|
+
fallbackQueryStoreCache.current = new import_store.QueryStoreCache();
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
store: resolvedStore,
|
|
92
|
+
syncEngine: resolvedSync,
|
|
93
|
+
app: app ?? null,
|
|
94
|
+
events: app?.events ?? null,
|
|
95
|
+
subscribeSyncStatus: app?.sync?.subscribeStatus ?? null,
|
|
96
|
+
queryStoreCache: app && typeof app.getQueryStoreCache === "function" ? app.getQueryStoreCache() : fallbackQueryStoreCache.current
|
|
97
|
+
};
|
|
98
|
+
}, [resolvedStore, resolvedSync, app]);
|
|
99
|
+
if (initError) {
|
|
100
|
+
return (0, import_react.createElement)(
|
|
101
|
+
"div",
|
|
102
|
+
{ style: { color: "red", padding: "1rem", fontFamily: "monospace" } },
|
|
103
|
+
(0, import_react.createElement)("strong", null, "Kora initialization error: "),
|
|
104
|
+
initError.message
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
if (!ready) {
|
|
108
|
+
return fallback ?? null;
|
|
109
|
+
}
|
|
110
|
+
if (!contextValue) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
'KoraProvider requires either an "app" or "store" prop. Pass a KoraApp from createApp() or a Store instance.'
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
return (0, import_react.createElement)(KoraContext.Provider, { value: contextValue }, children);
|
|
116
|
+
}
|
|
117
|
+
function useKoraContext() {
|
|
118
|
+
const context = (0, import_react.useContext)(KoraContext);
|
|
119
|
+
if (context === null) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
"useKoraContext must be used within a <KoraProvider>. Wrap your component tree with <KoraProvider store={store}>."
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return context;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/context/auth-bound-kora-provider.ts
|
|
128
|
+
var import_react2 = require("react");
|
|
129
|
+
var SENSITIVE_METADATA_KEY = /token|secret|password|authorization|cookie/i;
|
|
130
|
+
function classifyKoraInitializationError(error) {
|
|
131
|
+
const candidate = error;
|
|
132
|
+
const message = typeof candidate?.message === "string" ? candidate.message : String(error);
|
|
133
|
+
const name = typeof candidate?.name === "string" ? candidate.name : "Error";
|
|
134
|
+
const cause = new Error(message);
|
|
135
|
+
cause.name = name;
|
|
136
|
+
if (typeof candidate?.stack === "string") cause.stack = candidate.stack;
|
|
137
|
+
let code = typeof candidate?.code === "string" ? candidate.code : "INITIALIZATION_FAILED";
|
|
138
|
+
if (code === "INITIALIZATION_FAILED" && cause.name === "QuotaExceededError") {
|
|
139
|
+
code = "STORAGE_QUOTA_EXCEEDED";
|
|
140
|
+
}
|
|
141
|
+
const metadata = {};
|
|
142
|
+
if (candidate?.context && typeof candidate.context === "object") {
|
|
143
|
+
for (const [key, value] of Object.entries(candidate.context)) {
|
|
144
|
+
if (SENSITIVE_METADATA_KEY.test(key)) continue;
|
|
145
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null) {
|
|
146
|
+
metadata[key] = value;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return { code, name: cause.name, message: cause.message, metadata, cause };
|
|
151
|
+
}
|
|
152
|
+
function AuthBoundKoraProvider({
|
|
153
|
+
authClient,
|
|
154
|
+
createApp,
|
|
155
|
+
signedOut = null,
|
|
156
|
+
locked,
|
|
157
|
+
fallback = null,
|
|
158
|
+
error: renderError,
|
|
159
|
+
children
|
|
160
|
+
}) {
|
|
161
|
+
const [app, setApp] = (0, import_react2.useState)(null);
|
|
162
|
+
const [state, setState] = (0, import_react2.useState)({ state: "loading" });
|
|
163
|
+
const [initError, setInitError] = (0, import_react2.useState)(null);
|
|
164
|
+
const active = (0, import_react2.useRef)(null);
|
|
165
|
+
const createAppRef = (0, import_react2.useRef)(createApp);
|
|
166
|
+
createAppRef.current = createApp;
|
|
167
|
+
const activeUserId = (0, import_react2.useRef)(null);
|
|
168
|
+
const generation = (0, import_react2.useRef)(0);
|
|
169
|
+
const transition = (0, import_react2.useRef)(Promise.resolve());
|
|
170
|
+
const reconcileRef = (0, import_react2.useRef)(() => {
|
|
171
|
+
});
|
|
172
|
+
(0, import_react2.useEffect)(() => {
|
|
173
|
+
let disposed = false;
|
|
174
|
+
const reconcile = () => {
|
|
175
|
+
const currentGeneration = ++generation.current;
|
|
176
|
+
transition.current = transition.current.catch(() => {
|
|
177
|
+
}).then(async () => {
|
|
178
|
+
setInitError(null);
|
|
179
|
+
const next = await authClient.resolveSyncState?.() ?? { state: "signed-out", mayConnectAnonymously: false };
|
|
180
|
+
if (disposed || currentGeneration !== generation.current) return;
|
|
181
|
+
const previous = active.current;
|
|
182
|
+
if (next.state === "authenticated" && next.userId === activeUserId.current && previous) {
|
|
183
|
+
setState(next);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
setApp(null);
|
|
187
|
+
active.current = null;
|
|
188
|
+
activeUserId.current = null;
|
|
189
|
+
if (previous) await previous.close();
|
|
190
|
+
if (disposed || currentGeneration !== generation.current) return;
|
|
191
|
+
setState(next);
|
|
192
|
+
if (next.state !== "authenticated") return;
|
|
193
|
+
const created = createAppRef.current(next);
|
|
194
|
+
try {
|
|
195
|
+
await created.ready;
|
|
196
|
+
} catch (error) {
|
|
197
|
+
await created.close();
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
if (disposed || currentGeneration !== generation.current) {
|
|
201
|
+
await created.close();
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
active.current = created;
|
|
205
|
+
activeUserId.current = next.userId;
|
|
206
|
+
setApp(created);
|
|
207
|
+
}).catch((error) => {
|
|
208
|
+
if (!disposed && currentGeneration === generation.current) {
|
|
209
|
+
void authClient.resolveSyncState?.().then((failedSession) => {
|
|
210
|
+
if (!disposed && currentGeneration === generation.current && failedSession?.state === "authenticated") {
|
|
211
|
+
setInitError({
|
|
212
|
+
error: classifyKoraInitializationError(error),
|
|
213
|
+
session: { userId: failedSession.userId }
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
reconcileRef.current = reconcile;
|
|
221
|
+
reconcile();
|
|
222
|
+
const unsubscribe = authClient.subscribe?.(reconcile) ?? (() => {
|
|
223
|
+
});
|
|
224
|
+
return () => {
|
|
225
|
+
disposed = true;
|
|
226
|
+
generation.current++;
|
|
227
|
+
unsubscribe();
|
|
228
|
+
const previous = active.current;
|
|
229
|
+
active.current = null;
|
|
230
|
+
activeUserId.current = null;
|
|
231
|
+
if (previous) void previous.close();
|
|
232
|
+
};
|
|
233
|
+
}, [authClient]);
|
|
234
|
+
if (initError) {
|
|
235
|
+
if (renderError) {
|
|
236
|
+
return renderError({
|
|
237
|
+
error: initError.error,
|
|
238
|
+
session: initError.session,
|
|
239
|
+
retry: () => reconcileRef.current()
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
return (0, import_react2.createElement)(
|
|
243
|
+
"div",
|
|
244
|
+
{ style: { color: "red", padding: "1rem", fontFamily: "monospace" } },
|
|
245
|
+
(0, import_react2.createElement)("strong", null, "Kora initialization error: "),
|
|
246
|
+
initError.error.message
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
if (state.state === "signed-out" || state.state === "anonymous") return signedOut;
|
|
250
|
+
if (state.state === "authenticated" && state.locked) return locked ?? signedOut;
|
|
251
|
+
if (!app) return fallback;
|
|
252
|
+
return (0, import_react2.createElement)(KoraProvider, { app, fallback }, children);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/hooks/use-app.ts
|
|
256
|
+
function useApp() {
|
|
257
|
+
const { app } = useKoraContext();
|
|
258
|
+
if (!app) {
|
|
259
|
+
throw new Error(
|
|
260
|
+
'useApp() requires KoraProvider to be initialized with an "app" prop. Pass your createApp() result to <KoraProvider app={app}>.'
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
return app;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// src/hooks/use-query.ts
|
|
267
|
+
var import_store2 = require("@korajs/store");
|
|
268
|
+
var import_react3 = require("react");
|
|
269
|
+
var EMPTY_ARRAY = Object.freeze([]);
|
|
270
|
+
var noopSubscribe = (_onStoreChange) => {
|
|
271
|
+
return () => {
|
|
272
|
+
};
|
|
273
|
+
};
|
|
274
|
+
var getServerSnapshot = () => EMPTY_ARRAY;
|
|
275
|
+
var getNoError = () => null;
|
|
276
|
+
function readQueryError(queryStore) {
|
|
277
|
+
if (!queryStore) return null;
|
|
278
|
+
const channel = queryStore;
|
|
279
|
+
return typeof channel.getError === "function" ? channel.getError() : null;
|
|
280
|
+
}
|
|
281
|
+
function useQuerySubscription(query, options) {
|
|
282
|
+
const { queryStoreCache } = useKoraContext();
|
|
283
|
+
const enabled = options?.enabled !== false;
|
|
284
|
+
const descriptorKey = (0, import_store2.queryKey)(query.getDescriptor());
|
|
285
|
+
const queryRef = (0, import_react3.useRef)(query);
|
|
286
|
+
queryRef.current = query;
|
|
287
|
+
const lastSnapshotRef = (0, import_react3.useRef)(EMPTY_ARRAY);
|
|
288
|
+
const [queryStore, setQueryStore] = (0, import_react3.useState)(null);
|
|
289
|
+
(0, import_react3.useEffect)(() => {
|
|
290
|
+
if (!enabled) {
|
|
291
|
+
setQueryStore(null);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const currentQuery = queryRef.current;
|
|
295
|
+
(0, import_store2.assertQueryReady)(currentQuery);
|
|
296
|
+
const store = queryStoreCache.getOrCreate(currentQuery);
|
|
297
|
+
setQueryStore(store);
|
|
298
|
+
return () => {
|
|
299
|
+
queryStoreCache.release(currentQuery);
|
|
300
|
+
};
|
|
301
|
+
}, [descriptorKey, enabled, queryStoreCache]);
|
|
302
|
+
const subscribe = enabled && queryStore ? queryStore.subscribe : noopSubscribe;
|
|
303
|
+
const getSnapshot = (0, import_react3.useCallback)(() => {
|
|
304
|
+
if (!enabled) {
|
|
305
|
+
lastSnapshotRef.current = EMPTY_ARRAY;
|
|
306
|
+
return lastSnapshotRef.current;
|
|
307
|
+
}
|
|
308
|
+
if (!queryStore || !queryStore.hasSnapshot()) {
|
|
309
|
+
return lastSnapshotRef.current;
|
|
310
|
+
}
|
|
311
|
+
const snapshot = queryStore.getSnapshot();
|
|
312
|
+
lastSnapshotRef.current = snapshot;
|
|
313
|
+
return snapshot;
|
|
314
|
+
}, [enabled, queryStore]);
|
|
315
|
+
const getError = (0, import_react3.useCallback)(
|
|
316
|
+
() => enabled ? readQueryError(queryStore) : null,
|
|
317
|
+
[enabled, queryStore]
|
|
318
|
+
);
|
|
319
|
+
const data = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
|
|
320
|
+
const error = (0, import_react3.useSyncExternalStore)(subscribe, getError, getNoError);
|
|
321
|
+
const ready = enabled && queryStore !== null && queryStore.hasSnapshot();
|
|
322
|
+
return { data, error, ready };
|
|
323
|
+
}
|
|
324
|
+
function useQuery(query, options) {
|
|
325
|
+
const { data, error } = useQuerySubscription(query, options);
|
|
326
|
+
if (error && options?.throwOnError !== false) {
|
|
327
|
+
throw error;
|
|
328
|
+
}
|
|
329
|
+
return data;
|
|
330
|
+
}
|
|
331
|
+
function useQueryState(query, options) {
|
|
332
|
+
const { data, error, ready } = useQuerySubscription(query, options);
|
|
333
|
+
return (0, import_react3.useMemo)(() => ({ data, error, ready }), [data, error, ready]);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// src/hooks/create-kora-hooks.ts
|
|
337
|
+
var import_react7 = require("react");
|
|
338
|
+
|
|
339
|
+
// src/hooks/use-mutation.ts
|
|
340
|
+
var import_bindings = require("@korajs/core/bindings");
|
|
341
|
+
var import_react5 = require("react");
|
|
342
|
+
|
|
343
|
+
// src/hooks/use-controller.ts
|
|
344
|
+
var import_react4 = require("react");
|
|
345
|
+
var ORPHAN_REAP_MS = 1e3;
|
|
346
|
+
function useController(create, destroy, deps) {
|
|
347
|
+
const entryRef = (0, import_react4.useRef)(null);
|
|
348
|
+
const createRef = (0, import_react4.useRef)(create);
|
|
349
|
+
createRef.current = create;
|
|
350
|
+
const destroyRef = (0, import_react4.useRef)(destroy);
|
|
351
|
+
destroyRef.current = destroy;
|
|
352
|
+
const [version, bumpVersion] = (0, import_react4.useReducer)((count) => count + 1, 0);
|
|
353
|
+
const handle = (0, import_react4.useRef)({
|
|
354
|
+
get: () => {
|
|
355
|
+
const current = entryRef.current;
|
|
356
|
+
if (current !== null && !current.reaped) {
|
|
357
|
+
return current.controller;
|
|
358
|
+
}
|
|
359
|
+
const entry = {
|
|
360
|
+
controller: createRef.current(),
|
|
361
|
+
claimed: false,
|
|
362
|
+
reaped: false
|
|
363
|
+
};
|
|
364
|
+
entryRef.current = entry;
|
|
365
|
+
setTimeout(() => {
|
|
366
|
+
if (!entry.claimed && !entry.reaped) {
|
|
367
|
+
entry.reaped = true;
|
|
368
|
+
destroyRef.current(entry.controller);
|
|
369
|
+
}
|
|
370
|
+
}, ORPHAN_REAP_MS);
|
|
371
|
+
return entry.controller;
|
|
372
|
+
},
|
|
373
|
+
peek: () => {
|
|
374
|
+
const current = entryRef.current;
|
|
375
|
+
return current?.claimed && !current.reaped ? current.controller : null;
|
|
376
|
+
}
|
|
377
|
+
}).current;
|
|
378
|
+
(0, import_react4.useEffect)(() => {
|
|
379
|
+
const current = entryRef.current;
|
|
380
|
+
if (current !== null && !current.reaped && !current.claimed) {
|
|
381
|
+
current.claimed = true;
|
|
382
|
+
} else if (current === null || current.reaped) {
|
|
383
|
+
entryRef.current = { controller: createRef.current(), claimed: true, reaped: false };
|
|
384
|
+
bumpVersion();
|
|
385
|
+
}
|
|
386
|
+
return () => {
|
|
387
|
+
const entry = entryRef.current;
|
|
388
|
+
entryRef.current = null;
|
|
389
|
+
if (entry !== null && !entry.reaped) {
|
|
390
|
+
entry.reaped = true;
|
|
391
|
+
destroyRef.current(entry.controller);
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
}, deps);
|
|
395
|
+
return { get: handle.get, peek: handle.peek, version };
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// src/hooks/use-mutation.ts
|
|
399
|
+
var IDLE = Object.freeze({ isLoading: false, error: null });
|
|
400
|
+
var getServerSnapshot2 = () => IDLE;
|
|
401
|
+
function useMutation(mutationFn, options) {
|
|
402
|
+
const fnRef = (0, import_react5.useRef)(mutationFn);
|
|
403
|
+
fnRef.current = mutationFn;
|
|
404
|
+
const optionsRef = (0, import_react5.useRef)(options);
|
|
405
|
+
optionsRef.current = options;
|
|
406
|
+
const controller = useController(
|
|
407
|
+
() => (0, import_bindings.createMutationController)({
|
|
408
|
+
mutationFn: (...args) => fnRef.current(...args),
|
|
409
|
+
resolveOptions: () => optionsRef.current
|
|
410
|
+
}),
|
|
411
|
+
(instance) => instance.destroy(),
|
|
412
|
+
[]
|
|
413
|
+
);
|
|
414
|
+
const getController = controller.get;
|
|
415
|
+
const subscribe = (0, import_react5.useCallback)(
|
|
416
|
+
(onStoreChange) => getController().subscribe(onStoreChange),
|
|
417
|
+
[getController, controller.version]
|
|
418
|
+
);
|
|
419
|
+
const getSnapshot = (0, import_react5.useCallback)(() => getController().getSnapshot(), [getController]);
|
|
420
|
+
const state = (0, import_react5.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot2);
|
|
421
|
+
const mutate = (0, import_react5.useCallback)((...args) => getController().mutate(...args), [getController]);
|
|
422
|
+
const mutateAsync = (0, import_react5.useCallback)(
|
|
423
|
+
(...args) => getController().mutateAsync(...args),
|
|
424
|
+
[getController]
|
|
425
|
+
);
|
|
426
|
+
const reset = (0, import_react5.useCallback)(() => getController().reset(), [getController]);
|
|
427
|
+
return (0, import_react5.useMemo)(
|
|
428
|
+
() => ({ mutate, mutateAsync, isLoading: state.isLoading, error: state.error, reset }),
|
|
429
|
+
[mutate, mutateAsync, reset, state.isLoading, state.error]
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// src/hooks/use-sync-status.ts
|
|
434
|
+
var import_sync = require("@korajs/sync");
|
|
435
|
+
var import_react6 = require("react");
|
|
436
|
+
var getServerSnapshot3 = () => import_sync.OFFLINE_SYNC_STATUS;
|
|
437
|
+
function useSyncStatus() {
|
|
438
|
+
const { syncEngine, subscribeSyncStatus, events } = useKoraContext();
|
|
439
|
+
const controller = useController(
|
|
440
|
+
() => (0, import_sync.createSyncStatusController)({
|
|
441
|
+
syncEngine,
|
|
442
|
+
subscribeSyncStatus,
|
|
443
|
+
events: subscribeSyncStatus ? null : events
|
|
444
|
+
}),
|
|
445
|
+
(instance) => instance.destroy(),
|
|
446
|
+
[syncEngine, subscribeSyncStatus, events]
|
|
447
|
+
);
|
|
448
|
+
const getController = controller.get;
|
|
449
|
+
const subscribe = (0, import_react6.useCallback)(
|
|
450
|
+
(onStoreChange) => getController().subscribe(onStoreChange),
|
|
451
|
+
[getController, controller.version]
|
|
452
|
+
);
|
|
453
|
+
const peek = controller.peek;
|
|
454
|
+
const getSnapshot = (0, import_react6.useCallback)(
|
|
455
|
+
() => peek()?.getSnapshot() ?? import_sync.OFFLINE_SYNC_STATUS,
|
|
456
|
+
[peek]
|
|
457
|
+
);
|
|
458
|
+
return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot3);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// src/hooks/create-kora-hooks.ts
|
|
462
|
+
function createKoraHooks() {
|
|
463
|
+
function useTypedApp() {
|
|
464
|
+
return useApp();
|
|
465
|
+
}
|
|
466
|
+
function useTypedCollection(name) {
|
|
467
|
+
const { app, store } = useKoraContext();
|
|
468
|
+
return (0, import_react7.useMemo)(() => {
|
|
469
|
+
const collections = app?.collections;
|
|
470
|
+
const accessor = collections && name in collections ? collections[name] : store.collection(name);
|
|
471
|
+
return accessor;
|
|
472
|
+
}, [app, store, name]);
|
|
473
|
+
}
|
|
474
|
+
return {
|
|
475
|
+
useApp: useTypedApp,
|
|
476
|
+
useCollection: useTypedCollection,
|
|
477
|
+
useQuery,
|
|
478
|
+
useQueryState,
|
|
479
|
+
useMutation,
|
|
480
|
+
useSyncStatus
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// src/hooks/use-collection.ts
|
|
485
|
+
var import_react8 = require("react");
|
|
486
|
+
function useCollection(name) {
|
|
487
|
+
const { store } = useKoraContext();
|
|
488
|
+
return (0, import_react8.useMemo)(() => {
|
|
489
|
+
return store.collection(name);
|
|
490
|
+
}, [store, name]);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// src/hooks/use-rich-text.ts
|
|
494
|
+
var import_store3 = require("@korajs/store");
|
|
495
|
+
var import_react9 = require("react");
|
|
496
|
+
function useRichText(collectionName, recordId, fieldName, options) {
|
|
497
|
+
const { store, syncEngine } = useKoraContext();
|
|
498
|
+
const collection = (0, import_react9.useMemo)(() => store.collection(collectionName), [store, collectionName]);
|
|
499
|
+
const controller = useController(
|
|
500
|
+
() => (0, import_store3.createRichTextController)({
|
|
501
|
+
collection,
|
|
502
|
+
collectionName,
|
|
503
|
+
recordId,
|
|
504
|
+
fieldName,
|
|
505
|
+
store,
|
|
506
|
+
syncEngine: (0, import_store3.asRichTextSyncEngine)(syncEngine),
|
|
507
|
+
useDocChannel: options?.useDocChannel,
|
|
508
|
+
user: options?.user
|
|
509
|
+
}),
|
|
510
|
+
(instance) => instance.destroy(),
|
|
511
|
+
[collection, collectionName, fieldName, options?.useDocChannel, recordId, store, syncEngine]
|
|
512
|
+
);
|
|
513
|
+
const getController = controller.get;
|
|
514
|
+
(0, import_react9.useEffect)(() => {
|
|
515
|
+
getController().setUser(options?.user);
|
|
516
|
+
}, [getController, options?.user, controller.version]);
|
|
517
|
+
const subscribe = (0, import_react9.useCallback)(
|
|
518
|
+
(onStoreChange) => getController().subscribe(onStoreChange),
|
|
519
|
+
[getController, controller.version]
|
|
520
|
+
);
|
|
521
|
+
const getSnapshot = (0, import_react9.useCallback)(() => getController().getSnapshot(), [getController]);
|
|
522
|
+
const snapshot = (0, import_react9.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
523
|
+
const undo = (0, import_react9.useCallback)(() => {
|
|
524
|
+
getController().undo();
|
|
525
|
+
}, [getController]);
|
|
526
|
+
const redo = (0, import_react9.useCallback)(() => {
|
|
527
|
+
getController().redo();
|
|
528
|
+
}, [getController]);
|
|
529
|
+
const setCursor = (0, import_react9.useCallback)(
|
|
530
|
+
(anchor, head) => getController().setCursor(anchor, head),
|
|
531
|
+
[getController]
|
|
532
|
+
);
|
|
533
|
+
const clearCursor = (0, import_react9.useCallback)(() => getController().clearCursor(), [getController]);
|
|
534
|
+
const live = getController();
|
|
535
|
+
return (0, import_react9.useMemo)(
|
|
536
|
+
() => buildResult(live, snapshot, undo, redo, setCursor, clearCursor),
|
|
537
|
+
[live, snapshot, undo, redo, setCursor, clearCursor, controller.version]
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
function buildResult(controller, snapshot, undo, redo, setCursor, clearCursor) {
|
|
541
|
+
return {
|
|
542
|
+
doc: controller.doc,
|
|
543
|
+
text: controller.text,
|
|
544
|
+
undo,
|
|
545
|
+
redo,
|
|
546
|
+
canUndo: snapshot.canUndo,
|
|
547
|
+
canRedo: snapshot.canRedo,
|
|
548
|
+
ready: snapshot.ready,
|
|
549
|
+
error: snapshot.error,
|
|
550
|
+
cursors: [...snapshot.cursors],
|
|
551
|
+
setCursor,
|
|
552
|
+
clearCursor,
|
|
553
|
+
hasUnsavedChanges: snapshot.hasUnsavedChanges,
|
|
554
|
+
retrySave: () => controller.retrySave(),
|
|
555
|
+
getUnsavedState: () => controller.getUnsavedState()
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// src/hooks/use-presence.ts
|
|
560
|
+
var import_react10 = require("react");
|
|
561
|
+
function usePresence(user) {
|
|
562
|
+
const { syncEngine } = useKoraContext();
|
|
563
|
+
const name = user?.name ?? null;
|
|
564
|
+
const color = user?.color ?? null;
|
|
565
|
+
const avatar = user?.avatar ?? null;
|
|
566
|
+
(0, import_react10.useEffect)(() => {
|
|
567
|
+
if (!syncEngine || !name || !color) return;
|
|
568
|
+
const awareness = syncEngine.getAwarenessManager();
|
|
569
|
+
awareness.setLocalState({
|
|
570
|
+
user: { name, color, avatar: avatar ?? void 0 }
|
|
571
|
+
});
|
|
572
|
+
return () => {
|
|
573
|
+
awareness.setLocalState(null);
|
|
574
|
+
};
|
|
575
|
+
}, [syncEngine, name, color, avatar]);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// src/hooks/use-collaborators.ts
|
|
579
|
+
var import_sync2 = require("@korajs/sync");
|
|
580
|
+
var import_react11 = require("react");
|
|
581
|
+
var EMPTY_ARRAY2 = [];
|
|
582
|
+
var getServerSnapshot4 = () => EMPTY_ARRAY2;
|
|
583
|
+
function useCollaborators() {
|
|
584
|
+
const { syncEngine } = useKoraContext();
|
|
585
|
+
const snapshotRef = (0, import_react11.useRef)(EMPTY_ARRAY2);
|
|
586
|
+
const subscribe = (0, import_react11.useCallback)(
|
|
587
|
+
(onStoreChange) => {
|
|
588
|
+
if (!syncEngine) {
|
|
589
|
+
snapshotRef.current = EMPTY_ARRAY2;
|
|
590
|
+
return () => {
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
const awareness = syncEngine.getAwarenessManager();
|
|
594
|
+
snapshotRef.current = EMPTY_ARRAY2;
|
|
595
|
+
return (0, import_sync2.subscribeRemoteAwarenessStates)(awareness, (states) => {
|
|
596
|
+
snapshotRef.current = states;
|
|
597
|
+
onStoreChange();
|
|
598
|
+
});
|
|
599
|
+
},
|
|
600
|
+
[syncEngine]
|
|
601
|
+
);
|
|
602
|
+
const getSnapshot = (0, import_react11.useCallback)(() => snapshotRef.current, []);
|
|
603
|
+
(0, import_react11.useEffect)(() => {
|
|
604
|
+
if (!syncEngine) {
|
|
605
|
+
snapshotRef.current = EMPTY_ARRAY2;
|
|
606
|
+
}
|
|
607
|
+
}, [syncEngine]);
|
|
608
|
+
return (0, import_react11.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot4);
|
|
609
|
+
}
|
|
610
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
611
|
+
0 && (module.exports = {
|
|
612
|
+
AuthBoundKoraProvider,
|
|
613
|
+
KoraProvider,
|
|
614
|
+
classifyKoraInitializationError,
|
|
615
|
+
createKoraHooks,
|
|
616
|
+
useApp,
|
|
617
|
+
useCollaborators,
|
|
618
|
+
useCollection,
|
|
619
|
+
useMutation,
|
|
620
|
+
usePresence,
|
|
621
|
+
useQuery,
|
|
622
|
+
useQueryState,
|
|
623
|
+
useRichText,
|
|
624
|
+
useSyncStatus
|
|
625
|
+
});
|
|
626
|
+
//# sourceMappingURL=index.cjs.map
|