@topgunbuild/react 0.2.1 → 0.4.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.d.mts +580 -4
- package/dist/index.d.ts +580 -4
- package/dist/index.js +381 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +381 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -10
- package/LICENSE +0 -97
package/dist/index.js
CHANGED
|
@@ -22,9 +22,14 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
TopGunProvider: () => TopGunProvider,
|
|
24
24
|
useClient: () => useClient,
|
|
25
|
+
useConflictResolver: () => useConflictResolver,
|
|
26
|
+
useEntryProcessor: () => useEntryProcessor,
|
|
27
|
+
useEventJournal: () => useEventJournal,
|
|
25
28
|
useMap: () => useMap,
|
|
29
|
+
useMergeRejections: () => useMergeRejections,
|
|
26
30
|
useMutation: () => useMutation,
|
|
27
31
|
useORMap: () => useORMap,
|
|
32
|
+
usePNCounter: () => usePNCounter,
|
|
28
33
|
useQuery: () => useQuery,
|
|
29
34
|
useTopic: () => useTopic
|
|
30
35
|
});
|
|
@@ -47,27 +52,78 @@ function useClient() {
|
|
|
47
52
|
|
|
48
53
|
// src/hooks/useQuery.ts
|
|
49
54
|
var import_react2 = require("react");
|
|
50
|
-
function useQuery(mapName, query = {}) {
|
|
55
|
+
function useQuery(mapName, query = {}, options) {
|
|
51
56
|
const client = useClient();
|
|
52
57
|
const [data, setData] = (0, import_react2.useState)([]);
|
|
53
58
|
const [loading, setLoading] = (0, import_react2.useState)(true);
|
|
54
59
|
const [error, setError] = (0, import_react2.useState)(null);
|
|
60
|
+
const [changes, setChanges] = (0, import_react2.useState)([]);
|
|
61
|
+
const [lastChange, setLastChange] = (0, import_react2.useState)(null);
|
|
55
62
|
const isMounted = (0, import_react2.useRef)(true);
|
|
63
|
+
const handleRef = (0, import_react2.useRef)(null);
|
|
56
64
|
const queryJson = JSON.stringify(query);
|
|
65
|
+
const clearChanges = (0, import_react2.useCallback)(() => {
|
|
66
|
+
setChanges([]);
|
|
67
|
+
setLastChange(null);
|
|
68
|
+
}, []);
|
|
69
|
+
const optionsRef = (0, import_react2.useRef)(options);
|
|
70
|
+
optionsRef.current = options;
|
|
57
71
|
(0, import_react2.useEffect)(() => {
|
|
58
72
|
isMounted.current = true;
|
|
59
73
|
setLoading(true);
|
|
74
|
+
setChanges([]);
|
|
75
|
+
setLastChange(null);
|
|
60
76
|
try {
|
|
61
77
|
const handle = client.query(mapName, query);
|
|
62
|
-
|
|
78
|
+
handleRef.current = handle;
|
|
79
|
+
const unsubscribeData = handle.subscribe((results) => {
|
|
63
80
|
if (isMounted.current) {
|
|
64
81
|
setData(results);
|
|
65
82
|
setLoading(false);
|
|
66
83
|
}
|
|
67
84
|
});
|
|
85
|
+
const unsubscribeChanges = handle.onChanges((newChanges) => {
|
|
86
|
+
if (!isMounted.current) return;
|
|
87
|
+
const maxChanges = optionsRef.current?.maxChanges ?? 1e3;
|
|
88
|
+
setChanges((prev) => {
|
|
89
|
+
const combined = [...prev, ...newChanges];
|
|
90
|
+
if (combined.length > maxChanges) {
|
|
91
|
+
return combined.slice(-maxChanges);
|
|
92
|
+
}
|
|
93
|
+
return combined;
|
|
94
|
+
});
|
|
95
|
+
if (newChanges.length > 0) {
|
|
96
|
+
setLastChange(newChanges[newChanges.length - 1]);
|
|
97
|
+
}
|
|
98
|
+
const opts = optionsRef.current;
|
|
99
|
+
if (opts) {
|
|
100
|
+
for (const change of newChanges) {
|
|
101
|
+
opts.onChange?.(change);
|
|
102
|
+
switch (change.type) {
|
|
103
|
+
case "add":
|
|
104
|
+
if (change.value !== void 0) {
|
|
105
|
+
opts.onAdd?.(change.key, change.value);
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
case "update":
|
|
109
|
+
if (change.value !== void 0 && change.previousValue !== void 0) {
|
|
110
|
+
opts.onUpdate?.(change.key, change.value, change.previousValue);
|
|
111
|
+
}
|
|
112
|
+
break;
|
|
113
|
+
case "remove":
|
|
114
|
+
if (change.previousValue !== void 0) {
|
|
115
|
+
opts.onRemove?.(change.key, change.previousValue);
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
68
122
|
return () => {
|
|
69
123
|
isMounted.current = false;
|
|
70
|
-
|
|
124
|
+
unsubscribeData();
|
|
125
|
+
unsubscribeChanges();
|
|
126
|
+
handleRef.current = null;
|
|
71
127
|
};
|
|
72
128
|
} catch (err) {
|
|
73
129
|
if (isMounted.current) {
|
|
@@ -76,10 +132,14 @@ function useQuery(mapName, query = {}) {
|
|
|
76
132
|
}
|
|
77
133
|
return () => {
|
|
78
134
|
isMounted.current = false;
|
|
135
|
+
handleRef.current = null;
|
|
79
136
|
};
|
|
80
137
|
}
|
|
81
138
|
}, [client, mapName, queryJson]);
|
|
82
|
-
return
|
|
139
|
+
return (0, import_react2.useMemo)(
|
|
140
|
+
() => ({ data, loading, error, lastChange, changes, clearChanges }),
|
|
141
|
+
[data, loading, error, lastChange, changes, clearChanges]
|
|
142
|
+
);
|
|
83
143
|
}
|
|
84
144
|
|
|
85
145
|
// src/hooks/useMutation.ts
|
|
@@ -168,13 +228,330 @@ function useTopic(topicName, callback) {
|
|
|
168
228
|
}, [topic, callback]);
|
|
169
229
|
return topic;
|
|
170
230
|
}
|
|
231
|
+
|
|
232
|
+
// src/hooks/usePNCounter.ts
|
|
233
|
+
var import_react7 = require("react");
|
|
234
|
+
function usePNCounter(name) {
|
|
235
|
+
const client = useClient();
|
|
236
|
+
const [value, setValue] = (0, import_react7.useState)(0);
|
|
237
|
+
const [loading, setLoading] = (0, import_react7.useState)(true);
|
|
238
|
+
const counter = (0, import_react7.useMemo)(() => {
|
|
239
|
+
return client.getPNCounter(name);
|
|
240
|
+
}, [client, name]);
|
|
241
|
+
(0, import_react7.useEffect)(() => {
|
|
242
|
+
setLoading(true);
|
|
243
|
+
const unsubscribe = counter.subscribe((newValue) => {
|
|
244
|
+
setValue(newValue);
|
|
245
|
+
setLoading(false);
|
|
246
|
+
});
|
|
247
|
+
return unsubscribe;
|
|
248
|
+
}, [counter]);
|
|
249
|
+
const increment = (0, import_react7.useCallback)(() => {
|
|
250
|
+
counter.increment();
|
|
251
|
+
}, [counter]);
|
|
252
|
+
const decrement = (0, import_react7.useCallback)(() => {
|
|
253
|
+
counter.decrement();
|
|
254
|
+
}, [counter]);
|
|
255
|
+
const add = (0, import_react7.useCallback)((delta) => {
|
|
256
|
+
counter.addAndGet(delta);
|
|
257
|
+
}, [counter]);
|
|
258
|
+
return (0, import_react7.useMemo)(
|
|
259
|
+
() => ({ value, increment, decrement, add, loading }),
|
|
260
|
+
[value, increment, decrement, add, loading]
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/hooks/useEntryProcessor.ts
|
|
265
|
+
var import_react8 = require("react");
|
|
266
|
+
function useEntryProcessor(mapName, processorDef, options = {}) {
|
|
267
|
+
const client = useClient();
|
|
268
|
+
const [executing, setExecuting] = (0, import_react8.useState)(false);
|
|
269
|
+
const [lastResult, setLastResult] = (0, import_react8.useState)(null);
|
|
270
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
271
|
+
const { retries = 0, retryDelayMs = 100 } = options;
|
|
272
|
+
const execute = (0, import_react8.useCallback)(
|
|
273
|
+
async (key, args) => {
|
|
274
|
+
setExecuting(true);
|
|
275
|
+
setError(null);
|
|
276
|
+
const processor = {
|
|
277
|
+
...processorDef,
|
|
278
|
+
args
|
|
279
|
+
};
|
|
280
|
+
let attempts = 0;
|
|
281
|
+
let lastError = null;
|
|
282
|
+
while (attempts <= retries) {
|
|
283
|
+
try {
|
|
284
|
+
const result = await client.executeOnKey(mapName, key, processor);
|
|
285
|
+
setLastResult(result);
|
|
286
|
+
setExecuting(false);
|
|
287
|
+
return result;
|
|
288
|
+
} catch (err) {
|
|
289
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
290
|
+
attempts++;
|
|
291
|
+
if (attempts <= retries) {
|
|
292
|
+
const delay = retryDelayMs * Math.pow(2, attempts - 1);
|
|
293
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
setError(lastError);
|
|
298
|
+
setExecuting(false);
|
|
299
|
+
throw lastError;
|
|
300
|
+
},
|
|
301
|
+
[client, mapName, processorDef, retries, retryDelayMs]
|
|
302
|
+
);
|
|
303
|
+
const executeMany = (0, import_react8.useCallback)(
|
|
304
|
+
async (keys, args) => {
|
|
305
|
+
setExecuting(true);
|
|
306
|
+
setError(null);
|
|
307
|
+
const processor = {
|
|
308
|
+
...processorDef,
|
|
309
|
+
args
|
|
310
|
+
};
|
|
311
|
+
try {
|
|
312
|
+
const results = await client.executeOnKeys(mapName, keys, processor);
|
|
313
|
+
setExecuting(false);
|
|
314
|
+
return results;
|
|
315
|
+
} catch (err) {
|
|
316
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
317
|
+
setError(error2);
|
|
318
|
+
setExecuting(false);
|
|
319
|
+
throw error2;
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
[client, mapName, processorDef]
|
|
323
|
+
);
|
|
324
|
+
const reset = (0, import_react8.useCallback)(() => {
|
|
325
|
+
setLastResult(null);
|
|
326
|
+
setError(null);
|
|
327
|
+
}, []);
|
|
328
|
+
return (0, import_react8.useMemo)(
|
|
329
|
+
() => ({ execute, executeMany, executing, lastResult, error, reset }),
|
|
330
|
+
[execute, executeMany, executing, lastResult, error, reset]
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// src/hooks/useEventJournal.ts
|
|
335
|
+
var import_react9 = require("react");
|
|
336
|
+
function useEventJournal(options = {}) {
|
|
337
|
+
const client = useClient();
|
|
338
|
+
const [events, setEvents] = (0, import_react9.useState)([]);
|
|
339
|
+
const [lastEvent, setLastEvent] = (0, import_react9.useState)(null);
|
|
340
|
+
const [isSubscribed, setIsSubscribed] = (0, import_react9.useState)(false);
|
|
341
|
+
const isMounted = (0, import_react9.useRef)(true);
|
|
342
|
+
const journalRef = (0, import_react9.useRef)(null);
|
|
343
|
+
const maxEvents = options.maxEvents ?? 100;
|
|
344
|
+
const optionsRef = (0, import_react9.useRef)(options);
|
|
345
|
+
optionsRef.current = options;
|
|
346
|
+
const clearEvents = (0, import_react9.useCallback)(() => {
|
|
347
|
+
setEvents([]);
|
|
348
|
+
setLastEvent(null);
|
|
349
|
+
}, []);
|
|
350
|
+
const readFrom = (0, import_react9.useCallback)(
|
|
351
|
+
async (sequence, limit) => {
|
|
352
|
+
if (!journalRef.current) {
|
|
353
|
+
journalRef.current = client.getEventJournal();
|
|
354
|
+
}
|
|
355
|
+
return journalRef.current.readFrom(sequence, limit);
|
|
356
|
+
},
|
|
357
|
+
[client]
|
|
358
|
+
);
|
|
359
|
+
const getLatestSequence = (0, import_react9.useCallback)(async () => {
|
|
360
|
+
if (!journalRef.current) {
|
|
361
|
+
journalRef.current = client.getEventJournal();
|
|
362
|
+
}
|
|
363
|
+
return journalRef.current.getLatestSequence();
|
|
364
|
+
}, [client]);
|
|
365
|
+
const filterKey = (0, import_react9.useMemo)(
|
|
366
|
+
() => JSON.stringify({
|
|
367
|
+
mapName: options.mapName,
|
|
368
|
+
types: options.types,
|
|
369
|
+
fromSequence: options.fromSequence?.toString(),
|
|
370
|
+
paused: options.paused
|
|
371
|
+
}),
|
|
372
|
+
[options.mapName, options.types, options.fromSequence, options.paused]
|
|
373
|
+
);
|
|
374
|
+
(0, import_react9.useEffect)(() => {
|
|
375
|
+
isMounted.current = true;
|
|
376
|
+
if (options.paused) {
|
|
377
|
+
setIsSubscribed(false);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const journal = client.getEventJournal();
|
|
381
|
+
journalRef.current = journal;
|
|
382
|
+
const subscribeOptions = {
|
|
383
|
+
fromSequence: options.fromSequence,
|
|
384
|
+
mapName: options.mapName,
|
|
385
|
+
types: options.types
|
|
386
|
+
};
|
|
387
|
+
const unsubscribe = journal.subscribe((event) => {
|
|
388
|
+
if (!isMounted.current) return;
|
|
389
|
+
setEvents((prev) => {
|
|
390
|
+
const newEvents = [...prev, event];
|
|
391
|
+
if (newEvents.length > maxEvents) {
|
|
392
|
+
return newEvents.slice(-maxEvents);
|
|
393
|
+
}
|
|
394
|
+
return newEvents;
|
|
395
|
+
});
|
|
396
|
+
setLastEvent(event);
|
|
397
|
+
optionsRef.current.onEvent?.(event);
|
|
398
|
+
}, subscribeOptions);
|
|
399
|
+
setIsSubscribed(true);
|
|
400
|
+
return () => {
|
|
401
|
+
isMounted.current = false;
|
|
402
|
+
setIsSubscribed(false);
|
|
403
|
+
unsubscribe();
|
|
404
|
+
};
|
|
405
|
+
}, [client, filterKey, maxEvents]);
|
|
406
|
+
return (0, import_react9.useMemo)(
|
|
407
|
+
() => ({
|
|
408
|
+
events,
|
|
409
|
+
lastEvent,
|
|
410
|
+
clearEvents,
|
|
411
|
+
readFrom,
|
|
412
|
+
getLatestSequence,
|
|
413
|
+
isSubscribed
|
|
414
|
+
}),
|
|
415
|
+
[events, lastEvent, clearEvents, readFrom, getLatestSequence, isSubscribed]
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// src/hooks/useMergeRejections.ts
|
|
420
|
+
var import_react10 = require("react");
|
|
421
|
+
function useMergeRejections(options = {}) {
|
|
422
|
+
const client = useClient();
|
|
423
|
+
const { mapName, maxHistory = 100 } = options;
|
|
424
|
+
const [rejections, setRejections] = (0, import_react10.useState)([]);
|
|
425
|
+
const [lastRejection, setLastRejection] = (0, import_react10.useState)(null);
|
|
426
|
+
(0, import_react10.useEffect)(() => {
|
|
427
|
+
const resolvers = client.getConflictResolvers();
|
|
428
|
+
const unsubscribe = resolvers.onRejection((rejection) => {
|
|
429
|
+
if (mapName && rejection.mapName !== mapName) {
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
setLastRejection(rejection);
|
|
433
|
+
setRejections((prev) => {
|
|
434
|
+
const next = [...prev, rejection];
|
|
435
|
+
if (next.length > maxHistory) {
|
|
436
|
+
return next.slice(-maxHistory);
|
|
437
|
+
}
|
|
438
|
+
return next;
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
return unsubscribe;
|
|
442
|
+
}, [client, mapName, maxHistory]);
|
|
443
|
+
const clear = (0, import_react10.useCallback)(() => {
|
|
444
|
+
setRejections([]);
|
|
445
|
+
setLastRejection(null);
|
|
446
|
+
}, []);
|
|
447
|
+
return {
|
|
448
|
+
rejections,
|
|
449
|
+
lastRejection,
|
|
450
|
+
clear
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// src/hooks/useConflictResolver.ts
|
|
455
|
+
var import_react11 = require("react");
|
|
456
|
+
function useConflictResolver(mapName, options = {}) {
|
|
457
|
+
const client = useClient();
|
|
458
|
+
const { autoUnregister = true } = options;
|
|
459
|
+
const [loading, setLoading] = (0, import_react11.useState)(false);
|
|
460
|
+
const [error, setError] = (0, import_react11.useState)(null);
|
|
461
|
+
const [registered, setRegistered] = (0, import_react11.useState)([]);
|
|
462
|
+
(0, import_react11.useEffect)(() => {
|
|
463
|
+
return () => {
|
|
464
|
+
if (autoUnregister && registered.length > 0) {
|
|
465
|
+
const resolvers = client.getConflictResolvers();
|
|
466
|
+
for (const name of registered) {
|
|
467
|
+
resolvers.unregister(mapName, name).catch(() => {
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
}, [client, mapName, autoUnregister, registered]);
|
|
473
|
+
const register = (0, import_react11.useCallback)(
|
|
474
|
+
async (resolver) => {
|
|
475
|
+
setLoading(true);
|
|
476
|
+
setError(null);
|
|
477
|
+
try {
|
|
478
|
+
const resolvers = client.getConflictResolvers();
|
|
479
|
+
const result = await resolvers.register(mapName, resolver);
|
|
480
|
+
if (result.success) {
|
|
481
|
+
setRegistered((prev) => {
|
|
482
|
+
if (prev.includes(resolver.name)) {
|
|
483
|
+
return prev;
|
|
484
|
+
}
|
|
485
|
+
return [...prev, resolver.name];
|
|
486
|
+
});
|
|
487
|
+
} else if (result.error) {
|
|
488
|
+
setError(new Error(result.error));
|
|
489
|
+
}
|
|
490
|
+
return result;
|
|
491
|
+
} catch (e) {
|
|
492
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
493
|
+
setError(err);
|
|
494
|
+
return { success: false, error: err.message };
|
|
495
|
+
} finally {
|
|
496
|
+
setLoading(false);
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
[client, mapName]
|
|
500
|
+
);
|
|
501
|
+
const unregister = (0, import_react11.useCallback)(
|
|
502
|
+
async (resolverName) => {
|
|
503
|
+
setLoading(true);
|
|
504
|
+
setError(null);
|
|
505
|
+
try {
|
|
506
|
+
const resolvers = client.getConflictResolvers();
|
|
507
|
+
const result = await resolvers.unregister(mapName, resolverName);
|
|
508
|
+
if (result.success) {
|
|
509
|
+
setRegistered((prev) => prev.filter((n) => n !== resolverName));
|
|
510
|
+
} else if (result.error) {
|
|
511
|
+
setError(new Error(result.error));
|
|
512
|
+
}
|
|
513
|
+
return result;
|
|
514
|
+
} catch (e) {
|
|
515
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
516
|
+
setError(err);
|
|
517
|
+
return { success: false, error: err.message };
|
|
518
|
+
} finally {
|
|
519
|
+
setLoading(false);
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
[client, mapName]
|
|
523
|
+
);
|
|
524
|
+
const list = (0, import_react11.useCallback)(async () => {
|
|
525
|
+
try {
|
|
526
|
+
const resolvers = client.getConflictResolvers();
|
|
527
|
+
return await resolvers.list(mapName);
|
|
528
|
+
} catch (e) {
|
|
529
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
530
|
+
setError(err);
|
|
531
|
+
return [];
|
|
532
|
+
}
|
|
533
|
+
}, [client, mapName]);
|
|
534
|
+
return {
|
|
535
|
+
register,
|
|
536
|
+
unregister,
|
|
537
|
+
list,
|
|
538
|
+
loading,
|
|
539
|
+
error,
|
|
540
|
+
registered
|
|
541
|
+
};
|
|
542
|
+
}
|
|
171
543
|
// Annotate the CommonJS export names for ESM import in node:
|
|
172
544
|
0 && (module.exports = {
|
|
173
545
|
TopGunProvider,
|
|
174
546
|
useClient,
|
|
547
|
+
useConflictResolver,
|
|
548
|
+
useEntryProcessor,
|
|
549
|
+
useEventJournal,
|
|
175
550
|
useMap,
|
|
551
|
+
useMergeRejections,
|
|
176
552
|
useMutation,
|
|
177
553
|
useORMap,
|
|
554
|
+
usePNCounter,
|
|
178
555
|
useQuery,
|
|
179
556
|
useTopic
|
|
180
557
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/TopGunProvider.tsx","../src/hooks/useQuery.ts","../src/hooks/useMutation.ts","../src/hooks/useMap.ts","../src/hooks/useORMap.ts","../src/hooks/useTopic.ts"],"sourcesContent":["export * from './TopGunProvider';\nexport * from './hooks/useClient';\nexport * from './hooks/useQuery';\nexport * from './hooks/useMutation';\nexport * from './hooks/useMap';\nexport * from './hooks/useORMap';\nexport * from './hooks/useTopic';\n\n","import React, { createContext, useContext, ReactNode } from 'react';\nimport { TopGunClient } from '@topgunbuild/client';\n\nconst TopGunContext = createContext<TopGunClient | null>(null);\n\nexport interface TopGunProviderProps {\n client: TopGunClient;\n children: ReactNode;\n}\n\nexport const TopGunProvider: React.FC<TopGunProviderProps> = ({ client, children }) => {\n return (\n <TopGunContext.Provider value={client}>\n {children}\n </TopGunContext.Provider>\n );\n};\n\nexport function useClient(): TopGunClient {\n const client = useContext(TopGunContext);\n if (!client) {\n throw new Error('useClient must be used within a TopGunProvider');\n }\n return client;\n}\n\n","import { useState, useEffect, useRef } from 'react';\nimport { QueryFilter, QueryResultItem } from '@topgunbuild/client';\nimport { useClient } from './useClient';\n\nexport interface UseQueryResult<T> {\n data: QueryResultItem<T>[];\n loading: boolean;\n error: Error | null;\n}\n\nexport function useQuery<T = any>(mapName: string, query: QueryFilter = {}): UseQueryResult<T> {\n const client = useClient();\n const [data, setData] = useState<QueryResultItem<T>[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Use a ref to track if the component is mounted to avoid state updates on unmounted components\n const isMounted = useRef(true);\n\n // We serialize the query to use it as a stable dependency for the effect\n const queryJson = JSON.stringify(query);\n\n useEffect(() => {\n isMounted.current = true;\n setLoading(true);\n \n try {\n const handle = client.query<T>(mapName, query);\n\n const unsubscribe = handle.subscribe((results) => {\n if (isMounted.current) {\n setData(results);\n setLoading(false);\n }\n });\n\n return () => {\n isMounted.current = false;\n unsubscribe();\n };\n } catch (err) {\n if (isMounted.current) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setLoading(false);\n }\n return () => {\n isMounted.current = false;\n };\n }\n }, [client, mapName, queryJson]);\n\n return { data, loading, error };\n}\n\n","import { useCallback } from 'react';\nimport { useClient } from './useClient';\n\nexport interface UseMutationResult<T, K = string> {\n create: (key: K, value: T) => void;\n update: (key: K, value: T) => void;\n remove: (key: K) => void;\n map: any; // Expose map instance if needed\n}\n\nexport function useMutation<T = any, K = string>(mapName: string): UseMutationResult<T, K> {\n const client = useClient();\n // We get the map instance. Note: getMap is synchronous but might trigger async restore.\n // LWWMap is the default assumption for simple mutations.\n const map = client.getMap<K, T>(mapName);\n\n const create = useCallback((key: K, value: T) => {\n map.set(key, value);\n }, [map]);\n\n const update = useCallback((key: K, value: T) => {\n map.set(key, value);\n }, [map]);\n\n const remove = useCallback((key: K) => {\n map.remove(key);\n }, [map]);\n\n return { create, update, remove, map };\n}\n\n","import { useState, useEffect, useRef } from 'react';\nimport { LWWMap } from '@topgunbuild/core';\nimport { useClient } from './useClient';\n\nexport function useMap<K = string, V = any>(mapName: string): LWWMap<K, V> {\n const client = useClient();\n // Get the map instance. This is stable for the same mapName.\n const map = client.getMap<K, V>(mapName);\n\n // We use a dummy state to trigger re-renders when the map changes\n const [, setTick] = useState(0);\n const isMounted = useRef(true);\n\n useEffect(() => {\n isMounted.current = true;\n\n // Subscribe to map changes\n const unsubscribe = map.onChange(() => {\n if (isMounted.current) {\n setTick(t => t + 1);\n }\n });\n\n return () => {\n isMounted.current = false;\n unsubscribe();\n };\n }, [map]);\n\n return map;\n}\n","import { useState, useEffect, useRef } from 'react';\nimport { ORMap } from '@topgunbuild/core';\nimport { useClient } from './useClient';\n\nexport function useORMap<K = string, V = any>(mapName: string): ORMap<K, V> {\n const client = useClient();\n const map = client.getORMap<K, V>(mapName);\n\n const [, setTick] = useState(0);\n const isMounted = useRef(true);\n\n useEffect(() => {\n isMounted.current = true;\n\n const unsubscribe = map.onChange(() => {\n if (isMounted.current) {\n setTick(t => t + 1);\n }\n });\n\n return () => {\n isMounted.current = false;\n unsubscribe();\n };\n }, [map]);\n\n return map;\n}\n","import { useEffect, useRef } from 'react';\nimport { TopicCallback } from '@topgunbuild/client';\nimport { useClient } from './useClient';\n\nexport function useTopic(topicName: string, callback?: TopicCallback) {\n const client = useClient();\n const topic = client.topic(topicName);\n const isMounted = useRef(true);\n\n // Keep callback ref stable to avoid re-subscribing if callback function identity changes\n const callbackRef = useRef(callback);\n useEffect(() => {\n callbackRef.current = callback;\n }, [callback]);\n\n useEffect(() => {\n isMounted.current = true;\n\n if (!callback) return;\n\n const unsubscribe = topic.subscribe((data, context) => {\n if (isMounted.current && callbackRef.current) {\n callbackRef.current(data, context);\n }\n });\n\n return () => {\n isMounted.current = false;\n unsubscribe();\n };\n }, [topic, callback]); // Re-subscribe if topic handle changes (rare) or if callback presence toggles\n\n return topic;\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/TopGunProvider.tsx","../src/hooks/useQuery.ts","../src/hooks/useMutation.ts","../src/hooks/useMap.ts","../src/hooks/useORMap.ts","../src/hooks/useTopic.ts","../src/hooks/usePNCounter.ts","../src/hooks/useEntryProcessor.ts","../src/hooks/useEventJournal.ts","../src/hooks/useMergeRejections.ts","../src/hooks/useConflictResolver.ts"],"sourcesContent":["export * from './TopGunProvider';\nexport * from './hooks/useClient';\nexport * from './hooks/useQuery';\nexport * from './hooks/useMutation';\nexport * from './hooks/useMap';\nexport * from './hooks/useORMap';\nexport * from './hooks/useTopic';\nexport * from './hooks/usePNCounter';\nexport * from './hooks/useEntryProcessor';\nexport * from './hooks/useEventJournal';\n\n// Conflict Resolver hooks (Phase 5.05)\nexport * from './hooks/useMergeRejections';\nexport * from './hooks/useConflictResolver';\n","import React, { createContext, useContext, ReactNode } from 'react';\nimport { TopGunClient } from '@topgunbuild/client';\n\nconst TopGunContext = createContext<TopGunClient | null>(null);\n\nexport interface TopGunProviderProps {\n client: TopGunClient;\n children: ReactNode;\n}\n\nexport const TopGunProvider: React.FC<TopGunProviderProps> = ({ client, children }) => {\n return (\n <TopGunContext.Provider value={client}>\n {children}\n </TopGunContext.Provider>\n );\n};\n\nexport function useClient(): TopGunClient {\n const client = useContext(TopGunContext);\n if (!client) {\n throw new Error('useClient must be used within a TopGunProvider');\n }\n return client;\n}\n\n","import { useState, useEffect, useRef, useCallback, useMemo } from 'react';\nimport { QueryFilter, QueryResultItem, ChangeEvent, QueryHandle } from '@topgunbuild/client';\nimport { useClient } from './useClient';\n\n/**\n * Options for useQuery change callbacks (Phase 5.1)\n */\nexport interface UseQueryOptions<T> {\n /** Called for any change event */\n onChange?: (change: ChangeEvent<T>) => void;\n /** Called when an item is added */\n onAdd?: (key: string, value: T) => void;\n /** Called when an item is updated */\n onUpdate?: (key: string, value: T, previous: T) => void;\n /** Called when an item is removed */\n onRemove?: (key: string, previous: T) => void;\n /**\n * Maximum number of changes to accumulate before auto-rotating.\n * When exceeded, oldest changes are removed to prevent memory leaks.\n * Default: 1000\n */\n maxChanges?: number;\n}\n\n/**\n * Result type for useQuery hook with change tracking (Phase 5.1)\n */\nexport interface UseQueryResult<T> {\n /** Current data array */\n data: QueryResultItem<T>[];\n /** Loading state */\n loading: boolean;\n /** Error if query failed */\n error: Error | null;\n /** Last change event (Phase 5.1) */\n lastChange: ChangeEvent<T> | null;\n /** All changes since last clearChanges() call (Phase 5.1) */\n changes: ChangeEvent<T>[];\n /** Clear accumulated changes (Phase 5.1) */\n clearChanges: () => void;\n}\n\n/**\n * React hook for querying data with real-time updates and change tracking.\n *\n * @example Basic usage with change tracking\n * ```tsx\n * function TodoList() {\n * const { data, lastChange } = useQuery<Todo>('todos');\n *\n * useEffect(() => {\n * if (lastChange?.type === 'add') {\n * toast.success(`New todo: ${lastChange.value.title}`);\n * }\n * }, [lastChange]);\n *\n * return <ul>{data.map(todo => <TodoItem key={todo._key} {...todo} />)}</ul>;\n * }\n * ```\n *\n * @example With callback-based notifications\n * ```tsx\n * function NotifyingTodoList() {\n * const { data } = useQuery<Todo>('todos', undefined, {\n * onAdd: (key, todo) => showNotification(`New: ${todo.title}`),\n * onRemove: (key, todo) => showNotification(`Removed: ${todo.title}`)\n * });\n *\n * return <ul>{data.map(todo => <TodoItem key={todo._key} {...todo} />)}</ul>;\n * }\n * ```\n *\n * @example With framer-motion animations\n * ```tsx\n * import { AnimatePresence, motion } from 'framer-motion';\n *\n * function AnimatedTodoList() {\n * const { data } = useQuery<Todo>('todos');\n *\n * return (\n * <AnimatePresence>\n * {data.map(todo => (\n * <motion.li\n * key={todo._key}\n * initial={{ opacity: 0, x: -20 }}\n * animate={{ opacity: 1, x: 0 }}\n * exit={{ opacity: 0, x: 20 }}\n * >\n * {todo.title}\n * </motion.li>\n * ))}\n * </AnimatePresence>\n * );\n * }\n * ```\n */\nexport function useQuery<T = any>(\n mapName: string,\n query: QueryFilter = {},\n options?: UseQueryOptions<T>\n): UseQueryResult<T> {\n const client = useClient();\n const [data, setData] = useState<QueryResultItem<T>[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Phase 5.1: Change tracking state\n const [changes, setChanges] = useState<ChangeEvent<T>[]>([]);\n const [lastChange, setLastChange] = useState<ChangeEvent<T> | null>(null);\n\n // Use a ref to track if the component is mounted to avoid state updates on unmounted components\n const isMounted = useRef(true);\n\n // Store handle ref for cleanup\n const handleRef = useRef<QueryHandle<T> | null>(null);\n\n // We serialize the query to use it as a stable dependency for the effect\n const queryJson = JSON.stringify(query);\n\n // Phase 5.1: Clear changes callback\n const clearChanges = useCallback(() => {\n setChanges([]);\n setLastChange(null);\n }, []);\n\n // Memoize options callbacks to avoid unnecessary effect runs\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n useEffect(() => {\n isMounted.current = true;\n setLoading(true);\n\n // Reset changes when query changes\n setChanges([]);\n setLastChange(null);\n\n try {\n const handle = client.query<T>(mapName, query);\n handleRef.current = handle;\n\n // Subscribe to data updates\n const unsubscribeData = handle.subscribe((results) => {\n if (isMounted.current) {\n setData(results);\n setLoading(false);\n }\n });\n\n // Phase 5.1: Subscribe to change events\n const unsubscribeChanges = handle.onChanges((newChanges) => {\n if (!isMounted.current) return;\n\n const maxChanges = optionsRef.current?.maxChanges ?? 1000;\n\n // Accumulate changes with rotation to prevent memory leaks\n setChanges((prev) => {\n const combined = [...prev, ...newChanges];\n // Rotate oldest changes if exceeding limit\n if (combined.length > maxChanges) {\n return combined.slice(-maxChanges);\n }\n return combined;\n });\n\n // Track last change\n if (newChanges.length > 0) {\n setLastChange(newChanges[newChanges.length - 1]);\n }\n\n // Invoke callbacks from options\n const opts = optionsRef.current;\n if (opts) {\n for (const change of newChanges) {\n opts.onChange?.(change);\n\n switch (change.type) {\n case 'add':\n if (change.value !== undefined) {\n opts.onAdd?.(change.key, change.value);\n }\n break;\n case 'update':\n if (change.value !== undefined && change.previousValue !== undefined) {\n opts.onUpdate?.(change.key, change.value, change.previousValue);\n }\n break;\n case 'remove':\n if (change.previousValue !== undefined) {\n opts.onRemove?.(change.key, change.previousValue);\n }\n break;\n }\n }\n }\n });\n\n return () => {\n isMounted.current = false;\n unsubscribeData();\n unsubscribeChanges();\n handleRef.current = null;\n };\n } catch (err) {\n if (isMounted.current) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setLoading(false);\n }\n return () => {\n isMounted.current = false;\n handleRef.current = null;\n };\n }\n }, [client, mapName, queryJson]);\n\n return useMemo(\n () => ({ data, loading, error, lastChange, changes, clearChanges }),\n [data, loading, error, lastChange, changes, clearChanges]\n );\n}\n","import { useCallback } from 'react';\nimport { useClient } from './useClient';\n\nexport interface UseMutationResult<T, K = string> {\n create: (key: K, value: T) => void;\n update: (key: K, value: T) => void;\n remove: (key: K) => void;\n map: any; // Expose map instance if needed\n}\n\nexport function useMutation<T = any, K = string>(mapName: string): UseMutationResult<T, K> {\n const client = useClient();\n // We get the map instance. Note: getMap is synchronous but might trigger async restore.\n // LWWMap is the default assumption for simple mutations.\n const map = client.getMap<K, T>(mapName);\n\n const create = useCallback((key: K, value: T) => {\n map.set(key, value);\n }, [map]);\n\n const update = useCallback((key: K, value: T) => {\n map.set(key, value);\n }, [map]);\n\n const remove = useCallback((key: K) => {\n map.remove(key);\n }, [map]);\n\n return { create, update, remove, map };\n}\n\n","import { useState, useEffect, useRef } from 'react';\nimport { LWWMap } from '@topgunbuild/core';\nimport { useClient } from './useClient';\n\nexport function useMap<K = string, V = any>(mapName: string): LWWMap<K, V> {\n const client = useClient();\n // Get the map instance. This is stable for the same mapName.\n const map = client.getMap<K, V>(mapName);\n\n // We use a dummy state to trigger re-renders when the map changes\n const [, setTick] = useState(0);\n const isMounted = useRef(true);\n\n useEffect(() => {\n isMounted.current = true;\n\n // Subscribe to map changes\n const unsubscribe = map.onChange(() => {\n if (isMounted.current) {\n setTick(t => t + 1);\n }\n });\n\n return () => {\n isMounted.current = false;\n unsubscribe();\n };\n }, [map]);\n\n return map;\n}\n","import { useState, useEffect, useRef } from 'react';\nimport { ORMap } from '@topgunbuild/core';\nimport { useClient } from './useClient';\n\nexport function useORMap<K = string, V = any>(mapName: string): ORMap<K, V> {\n const client = useClient();\n const map = client.getORMap<K, V>(mapName);\n\n const [, setTick] = useState(0);\n const isMounted = useRef(true);\n\n useEffect(() => {\n isMounted.current = true;\n\n const unsubscribe = map.onChange(() => {\n if (isMounted.current) {\n setTick(t => t + 1);\n }\n });\n\n return () => {\n isMounted.current = false;\n unsubscribe();\n };\n }, [map]);\n\n return map;\n}\n","import { useEffect, useRef } from 'react';\nimport { TopicCallback } from '@topgunbuild/client';\nimport { useClient } from './useClient';\n\nexport function useTopic(topicName: string, callback?: TopicCallback) {\n const client = useClient();\n const topic = client.topic(topicName);\n const isMounted = useRef(true);\n\n // Keep callback ref stable to avoid re-subscribing if callback function identity changes\n const callbackRef = useRef(callback);\n useEffect(() => {\n callbackRef.current = callback;\n }, [callback]);\n\n useEffect(() => {\n isMounted.current = true;\n\n if (!callback) return;\n\n const unsubscribe = topic.subscribe((data, context) => {\n if (isMounted.current && callbackRef.current) {\n callbackRef.current(data, context);\n }\n });\n\n return () => {\n isMounted.current = false;\n unsubscribe();\n };\n }, [topic, callback]); // Re-subscribe if topic handle changes (rare) or if callback presence toggles\n\n return topic;\n}\n","import { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useClient } from './useClient';\n\n/**\n * Result type for usePNCounter hook.\n */\nexport interface UsePNCounterResult {\n /** Current counter value */\n value: number;\n /** Increment the counter by 1 */\n increment: () => void;\n /** Decrement the counter by 1 */\n decrement: () => void;\n /** Add delta (positive or negative) to the counter */\n add: (delta: number) => void;\n /** Loading state (true until first value received) */\n loading: boolean;\n}\n\n/**\n * React hook for using a PN Counter with real-time updates.\n *\n * PN Counters support increment and decrement operations that work offline\n * and sync to server when connected. They guarantee convergence across\n * distributed nodes without coordination.\n *\n * @param name The counter name (e.g., 'likes:post-123')\n * @returns Counter value and methods\n *\n * @example Basic usage\n * ```tsx\n * function LikeButton({ postId }: { postId: string }) {\n * const { value, increment } = usePNCounter(`likes:${postId}`);\n *\n * return (\n * <button onClick={increment}>\n * ❤️ {value}\n * </button>\n * );\n * }\n * ```\n *\n * @example Inventory control\n * ```tsx\n * function InventoryControl({ productId }: { productId: string }) {\n * const { value, increment, decrement } = usePNCounter(`inventory:${productId}`);\n *\n * return (\n * <div>\n * <span>Stock: {value}</span>\n * <button onClick={decrement} disabled={value <= 0}>-</button>\n * <button onClick={increment}>+</button>\n * </div>\n * );\n * }\n * ```\n *\n * @example Bulk operations\n * ```tsx\n * function BulkAdd({ counterId }: { counterId: string }) {\n * const { value, add } = usePNCounter(counterId);\n * const [amount, setAmount] = useState(10);\n *\n * return (\n * <div>\n * <span>Value: {value}</span>\n * <input\n * type=\"number\"\n * value={amount}\n * onChange={(e) => setAmount(parseInt(e.target.value))}\n * />\n * <button onClick={() => add(amount)}>Add {amount}</button>\n * <button onClick={() => add(-amount)}>Subtract {amount}</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function usePNCounter(name: string): UsePNCounterResult {\n const client = useClient();\n const [value, setValue] = useState(0);\n const [loading, setLoading] = useState(true);\n\n // Get or create counter handle - memoized by name\n const counter = useMemo(() => {\n return client.getPNCounter(name);\n }, [client, name]);\n\n useEffect(() => {\n // Reset state when counter changes\n setLoading(true);\n\n const unsubscribe = counter.subscribe((newValue) => {\n setValue(newValue);\n setLoading(false);\n });\n\n return unsubscribe;\n }, [counter]);\n\n const increment = useCallback(() => {\n counter.increment();\n }, [counter]);\n\n const decrement = useCallback(() => {\n counter.decrement();\n }, [counter]);\n\n const add = useCallback((delta: number) => {\n counter.addAndGet(delta);\n }, [counter]);\n\n return useMemo(\n () => ({ value, increment, decrement, add, loading }),\n [value, increment, decrement, add, loading]\n );\n}\n","import { useState, useCallback, useMemo } from 'react';\nimport { useClient } from './useClient';\nimport type { EntryProcessorDef, EntryProcessorResult } from '@topgunbuild/core';\n\n/**\n * Options for the useEntryProcessor hook.\n */\nexport interface UseEntryProcessorOptions {\n /**\n * Number of retry attempts on failure.\n * Default: 0 (no retries)\n */\n retries?: number;\n\n /**\n * Delay between retries in milliseconds.\n * Default: 100ms, doubles with each retry (exponential backoff)\n */\n retryDelayMs?: number;\n}\n\n/**\n * Result type for useEntryProcessor hook.\n */\nexport interface UseEntryProcessorResult<R> {\n /**\n * Execute the processor on a key.\n * @param key The key to process\n * @param args Optional arguments to pass to the processor\n */\n execute: (key: string, args?: unknown) => Promise<EntryProcessorResult<R>>;\n\n /**\n * Execute the processor on multiple keys.\n * @param keys The keys to process\n * @param args Optional arguments to pass to the processor\n */\n executeMany: (keys: string[], args?: unknown) => Promise<Map<string, EntryProcessorResult<R>>>;\n\n /** True while a processor is executing */\n executing: boolean;\n\n /** Last execution result (single key) */\n lastResult: EntryProcessorResult<R> | null;\n\n /** Last error encountered */\n error: Error | null;\n\n /** Reset the hook state (clears lastResult and error) */\n reset: () => void;\n}\n\n/**\n * React hook for executing entry processors with loading and error states.\n *\n * Entry processors execute user-defined logic atomically on the server,\n * solving the read-modify-write race condition.\n *\n * @param mapName Name of the map to operate on\n * @param processorDef Processor definition (without args - args are passed per-execution)\n * @param options Optional configuration\n * @returns Execute function and state\n *\n * @example Basic increment\n * ```tsx\n * function LikeButton({ postId }: { postId: string }) {\n * const { execute, executing } = useEntryProcessor<number>('likes', {\n * name: 'increment',\n * code: `\n * const current = value ?? 0;\n * return { value: current + 1, result: current + 1 };\n * `,\n * });\n *\n * const handleLike = async () => {\n * const result = await execute(postId);\n * if (result.success) {\n * console.log('New like count:', result.result);\n * }\n * };\n *\n * return (\n * <button onClick={handleLike} disabled={executing}>\n * {executing ? '...' : 'Like'}\n * </button>\n * );\n * }\n * ```\n *\n * @example Inventory reservation with args\n * ```tsx\n * function ReserveButton({ productId }: { productId: string }) {\n * const { execute, executing, error } = useEntryProcessor<\n * { stock: number; reserved: string[] },\n * { success: boolean; remaining: number }\n * >('inventory', {\n * name: 'reserve_item',\n * code: `\n * if (!value || value.stock <= 0) {\n * return { value, result: { success: false, remaining: 0 } };\n * }\n * const newValue = {\n * ...value,\n * stock: value.stock - 1,\n * reserved: [...value.reserved, args.userId],\n * };\n * return {\n * value: newValue,\n * result: { success: true, remaining: newValue.stock }\n * };\n * `,\n * });\n *\n * const handleReserve = async () => {\n * const result = await execute(productId, { userId: currentUser.id });\n * if (result.success && result.result?.success) {\n * toast.success(`Reserved! ${result.result.remaining} left`);\n * } else {\n * toast.error('Out of stock');\n * }\n * };\n *\n * return (\n * <button onClick={handleReserve} disabled={executing}>\n * {executing ? 'Reserving...' : 'Reserve'}\n * </button>\n * );\n * }\n * ```\n *\n * @example Using built-in processor\n * ```tsx\n * import { BuiltInProcessors } from '@topgunbuild/core';\n *\n * function DecrementStock({ productId }: { productId: string }) {\n * const processorDef = useMemo(\n * () => BuiltInProcessors.DECREMENT_FLOOR(1),\n * []\n * );\n *\n * const { execute, executing, lastResult } = useEntryProcessor<\n * number,\n * { newValue: number; wasFloored: boolean }\n * >('stock', processorDef);\n *\n * const handleDecrement = async () => {\n * const result = await execute(productId);\n * if (result.result?.wasFloored) {\n * alert('Stock is now at zero!');\n * }\n * };\n *\n * return (\n * <button onClick={handleDecrement} disabled={executing}>\n * Decrease Stock\n * </button>\n * );\n * }\n * ```\n */\nexport function useEntryProcessor<V = unknown, R = V>(\n mapName: string,\n processorDef: Omit<EntryProcessorDef<V, R>, 'args'>,\n options: UseEntryProcessorOptions = {},\n): UseEntryProcessorResult<R> {\n const client = useClient();\n const [executing, setExecuting] = useState(false);\n const [lastResult, setLastResult] = useState<EntryProcessorResult<R> | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n const { retries = 0, retryDelayMs = 100 } = options;\n\n const execute = useCallback(\n async (key: string, args?: unknown): Promise<EntryProcessorResult<R>> => {\n setExecuting(true);\n setError(null);\n\n const processor: EntryProcessorDef<V, R> = {\n ...processorDef,\n args,\n } as EntryProcessorDef<V, R>;\n\n let attempts = 0;\n let lastError: Error | null = null;\n\n while (attempts <= retries) {\n try {\n const result = await client.executeOnKey<V, R>(mapName, key, processor);\n setLastResult(result);\n setExecuting(false);\n return result;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n attempts++;\n\n if (attempts <= retries) {\n // Exponential backoff\n const delay = retryDelayMs * Math.pow(2, attempts - 1);\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n }\n\n // All retries exhausted\n setError(lastError);\n setExecuting(false);\n throw lastError;\n },\n [client, mapName, processorDef, retries, retryDelayMs],\n );\n\n const executeMany = useCallback(\n async (keys: string[], args?: unknown): Promise<Map<string, EntryProcessorResult<R>>> => {\n setExecuting(true);\n setError(null);\n\n const processor: EntryProcessorDef<V, R> = {\n ...processorDef,\n args,\n } as EntryProcessorDef<V, R>;\n\n try {\n const results = await client.executeOnKeys<V, R>(mapName, keys, processor);\n setExecuting(false);\n return results;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n setExecuting(false);\n throw error;\n }\n },\n [client, mapName, processorDef],\n );\n\n const reset = useCallback(() => {\n setLastResult(null);\n setError(null);\n }, []);\n\n return useMemo(\n () => ({ execute, executeMany, executing, lastResult, error, reset }),\n [execute, executeMany, executing, lastResult, error, reset],\n );\n}\n","import { useState, useEffect, useRef, useCallback, useMemo } from 'react';\nimport type { JournalEvent, JournalEventType } from '@topgunbuild/core';\nimport type { EventJournalReader, JournalSubscribeOptions } from '@topgunbuild/client';\nimport { useClient } from './useClient';\n\n/**\n * Options for useEventJournal hook.\n */\nexport interface UseEventJournalOptions {\n /** Start from specific sequence */\n fromSequence?: bigint;\n /** Filter by map name */\n mapName?: string;\n /** Filter by event types */\n types?: JournalEventType[];\n /** Maximum events to keep in state (default: 100) */\n maxEvents?: number;\n /** Called when new event is received */\n onEvent?: (event: JournalEvent) => void;\n /** Pause subscription */\n paused?: boolean;\n}\n\n/**\n * Result type for useEventJournal hook.\n */\nexport interface UseEventJournalResult {\n /** Array of recent events (newest last) */\n events: JournalEvent[];\n /** Last received event */\n lastEvent: JournalEvent | null;\n /** Clear accumulated events */\n clearEvents: () => void;\n /** Read historical events from sequence */\n readFrom: (sequence: bigint, limit?: number) => Promise<JournalEvent[]>;\n /** Get latest sequence number */\n getLatestSequence: () => Promise<bigint>;\n /** Whether subscription is active */\n isSubscribed: boolean;\n}\n\n/**\n * React hook for subscribing to Event Journal changes.\n *\n * The Event Journal captures all map changes (PUT, UPDATE, DELETE) as an\n * append-only log, useful for:\n * - Real-time activity feeds\n * - Audit trails\n * - Change notifications\n * - Debugging and monitoring\n *\n * @example Basic usage - show all changes\n * ```tsx\n * function ActivityFeed() {\n * const { events, lastEvent } = useEventJournal();\n *\n * return (\n * <ul>\n * {events.map((e) => (\n * <li key={e.sequence.toString()}>\n * {e.type} {e.mapName}:{e.key}\n * </li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n *\n * @example Filter by map name\n * ```tsx\n * function UserActivityFeed() {\n * const { events } = useEventJournal({ mapName: 'users' });\n *\n * return (\n * <ul>\n * {events.map((e) => (\n * <li key={e.sequence.toString()}>\n * User {e.key}: {e.type}\n * </li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n *\n * @example With event callback\n * ```tsx\n * function NotifyingComponent() {\n * const { events } = useEventJournal({\n * mapName: 'orders',\n * types: ['PUT'],\n * onEvent: (event) => {\n * toast.success(`New order: ${event.key}`);\n * },\n * });\n *\n * return <OrderList events={events} />;\n * }\n * ```\n */\nexport function useEventJournal(\n options: UseEventJournalOptions = {}\n): UseEventJournalResult {\n const client = useClient();\n const [events, setEvents] = useState<JournalEvent[]>([]);\n const [lastEvent, setLastEvent] = useState<JournalEvent | null>(null);\n const [isSubscribed, setIsSubscribed] = useState(false);\n\n const isMounted = useRef(true);\n const journalRef = useRef<EventJournalReader | null>(null);\n\n const maxEvents = options.maxEvents ?? 100;\n\n // Store options in ref to avoid re-subscription on every render\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n // Clear events callback\n const clearEvents = useCallback(() => {\n setEvents([]);\n setLastEvent(null);\n }, []);\n\n // Read historical events\n const readFrom = useCallback(\n async (sequence: bigint, limit?: number): Promise<JournalEvent[]> => {\n if (!journalRef.current) {\n journalRef.current = client.getEventJournal();\n }\n return journalRef.current.readFrom(sequence, limit);\n },\n [client]\n );\n\n // Get latest sequence\n const getLatestSequence = useCallback(async (): Promise<bigint> => {\n if (!journalRef.current) {\n journalRef.current = client.getEventJournal();\n }\n return journalRef.current.getLatestSequence();\n }, [client]);\n\n // Serialize filter options for dependency comparison\n const filterKey = useMemo(\n () =>\n JSON.stringify({\n mapName: options.mapName,\n types: options.types,\n fromSequence: options.fromSequence?.toString(),\n paused: options.paused,\n }),\n [options.mapName, options.types, options.fromSequence, options.paused]\n );\n\n useEffect(() => {\n isMounted.current = true;\n\n // Don't subscribe if paused\n if (options.paused) {\n setIsSubscribed(false);\n return;\n }\n\n const journal = client.getEventJournal();\n journalRef.current = journal;\n\n const subscribeOptions: JournalSubscribeOptions = {\n fromSequence: options.fromSequence,\n mapName: options.mapName,\n types: options.types,\n };\n\n const unsubscribe = journal.subscribe((event) => {\n if (!isMounted.current) return;\n\n // Add to events with rotation\n setEvents((prev) => {\n const newEvents = [...prev, event];\n if (newEvents.length > maxEvents) {\n return newEvents.slice(-maxEvents);\n }\n return newEvents;\n });\n\n setLastEvent(event);\n\n // Call event callback\n optionsRef.current.onEvent?.(event);\n }, subscribeOptions);\n\n setIsSubscribed(true);\n\n return () => {\n isMounted.current = false;\n setIsSubscribed(false);\n unsubscribe();\n };\n }, [client, filterKey, maxEvents]);\n\n return useMemo(\n () => ({\n events,\n lastEvent,\n clearEvents,\n readFrom,\n getLatestSequence,\n isSubscribed,\n }),\n [events, lastEvent, clearEvents, readFrom, getLatestSequence, isSubscribed]\n );\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport { useClient } from './useClient';\nimport type { MergeRejection } from '@topgunbuild/core';\n\n/**\n * Options for useMergeRejections hook.\n */\nexport interface UseMergeRejectionsOptions {\n /** Filter rejections by map name (optional) */\n mapName?: string;\n\n /** Maximum number of rejections to keep in history */\n maxHistory?: number;\n}\n\n/**\n * Result type for useMergeRejections hook.\n */\nexport interface UseMergeRejectionsResult {\n /** List of recent merge rejections */\n rejections: MergeRejection[];\n\n /** Last rejection received */\n lastRejection: MergeRejection | null;\n\n /** Clear rejection history */\n clear: () => void;\n}\n\n/**\n * React hook for subscribing to merge rejection events.\n *\n * Merge rejections occur when a custom conflict resolver rejects\n * a client's write operation. This hook allows you to:\n * - Display rejection notifications to users\n * - Refresh local state after rejection\n * - Log conflicts for debugging\n *\n * @param options Optional filtering and configuration\n * @returns Rejection list and utilities\n *\n * @example Show rejection notifications\n * ```tsx\n * function BookingForm() {\n * const { lastRejection, clear } = useMergeRejections({\n * mapName: 'bookings'\n * });\n *\n * useEffect(() => {\n * if (lastRejection) {\n * toast.error(`Booking failed: ${lastRejection.reason}`);\n * clear(); // Clear after showing notification\n * }\n * }, [lastRejection]);\n *\n * return <form>...</form>;\n * }\n * ```\n *\n * @example Track all rejections\n * ```tsx\n * function ConflictLog() {\n * const { rejections } = useMergeRejections({ maxHistory: 50 });\n *\n * return (\n * <ul>\n * {rejections.map((r, i) => (\n * <li key={i}>\n * {r.mapName}/{r.key}: {r.reason}\n * </li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useMergeRejections(\n options: UseMergeRejectionsOptions = {},\n): UseMergeRejectionsResult {\n const client = useClient();\n const { mapName, maxHistory = 100 } = options;\n\n const [rejections, setRejections] = useState<MergeRejection[]>([]);\n const [lastRejection, setLastRejection] = useState<MergeRejection | null>(null);\n\n useEffect(() => {\n const resolvers = client.getConflictResolvers();\n\n const unsubscribe = resolvers.onRejection((rejection) => {\n // Filter by map name if specified\n if (mapName && rejection.mapName !== mapName) {\n return;\n }\n\n setLastRejection(rejection);\n setRejections((prev) => {\n const next = [...prev, rejection];\n // Limit history size\n if (next.length > maxHistory) {\n return next.slice(-maxHistory);\n }\n return next;\n });\n });\n\n return unsubscribe;\n }, [client, mapName, maxHistory]);\n\n const clear = useCallback(() => {\n setRejections([]);\n setLastRejection(null);\n }, []);\n\n return {\n rejections,\n lastRejection,\n clear,\n };\n}\n","import { useState, useCallback, useEffect } from 'react';\nimport { useClient } from './useClient';\nimport type { ConflictResolverDef } from '@topgunbuild/core';\nimport type { ResolverInfo, RegisterResult } from '@topgunbuild/client';\n\n/**\n * Options for useConflictResolver hook.\n */\nexport interface UseConflictResolverOptions {\n /** Auto-unregister resolver on unmount (default: true) */\n autoUnregister?: boolean;\n}\n\n/**\n * Result type for useConflictResolver hook.\n */\nexport interface UseConflictResolverResult {\n /**\n * Register a conflict resolver on the server.\n * @param resolver The resolver definition\n */\n register: (resolver: Omit<ConflictResolverDef, 'fn'>) => Promise<RegisterResult>;\n\n /**\n * Unregister a resolver by name.\n * @param resolverName Name of the resolver to unregister\n */\n unregister: (resolverName: string) => Promise<RegisterResult>;\n\n /**\n * List all registered resolvers for this map.\n */\n list: () => Promise<ResolverInfo[]>;\n\n /** True while a registration/unregistration is in progress */\n loading: boolean;\n\n /** Last error encountered */\n error: Error | null;\n\n /** List of resolvers registered by this hook instance */\n registered: string[];\n}\n\n/**\n * React hook for managing conflict resolvers on a specific map.\n *\n * Conflict resolvers allow you to customize how merge conflicts are handled\n * on the server. This hook provides a convenient way to:\n * - Register custom resolvers\n * - Auto-unregister on component unmount\n * - Track registration state\n *\n * @param mapName Name of the map to manage resolvers for\n * @param options Optional configuration\n * @returns Resolver management functions and state\n *\n * @example First-write-wins for bookings\n * ```tsx\n * function BookingManager() {\n * const { register, registered, loading, error } = useConflictResolver('bookings');\n *\n * useEffect(() => {\n * // Register resolver on mount\n * register({\n * name: 'first-write-wins',\n * code: `\n * if (context.localValue !== undefined) {\n * return { action: 'reject', reason: 'Already booked' };\n * }\n * return { action: 'accept', value: context.remoteValue };\n * `,\n * priority: 100,\n * });\n * }, []);\n *\n * return (\n * <div>\n * {loading && <span>Registering...</span>}\n * {error && <span>Error: {error.message}</span>}\n * <ul>\n * {registered.map(name => <li key={name}>{name}</li>)}\n * </ul>\n * </div>\n * );\n * }\n * ```\n *\n * @example Numeric constraints\n * ```tsx\n * function InventorySettings() {\n * const { register } = useConflictResolver('inventory');\n *\n * const enableNonNegative = async () => {\n * await register({\n * name: 'non-negative',\n * code: `\n * if (context.remoteValue < 0) {\n * return { action: 'reject', reason: 'Stock cannot be negative' };\n * }\n * return { action: 'accept', value: context.remoteValue };\n * `,\n * priority: 90,\n * keyPattern: 'stock:*',\n * });\n * };\n *\n * return <button onClick={enableNonNegative}>Enable Stock Protection</button>;\n * }\n * ```\n */\nexport function useConflictResolver(\n mapName: string,\n options: UseConflictResolverOptions = {},\n): UseConflictResolverResult {\n const client = useClient();\n const { autoUnregister = true } = options;\n\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [registered, setRegistered] = useState<string[]>([]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (autoUnregister && registered.length > 0) {\n const resolvers = client.getConflictResolvers();\n // Fire-and-forget unregistration\n for (const name of registered) {\n resolvers.unregister(mapName, name).catch(() => {\n // Ignore errors on cleanup\n });\n }\n }\n };\n }, [client, mapName, autoUnregister, registered]);\n\n const register = useCallback(\n async (resolver: Omit<ConflictResolverDef, 'fn'>): Promise<RegisterResult> => {\n setLoading(true);\n setError(null);\n\n try {\n const resolvers = client.getConflictResolvers();\n const result = await resolvers.register(mapName, resolver);\n\n if (result.success) {\n setRegistered((prev) => {\n if (prev.includes(resolver.name)) {\n return prev;\n }\n return [...prev, resolver.name];\n });\n } else if (result.error) {\n setError(new Error(result.error));\n }\n\n return result;\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n return { success: false, error: err.message };\n } finally {\n setLoading(false);\n }\n },\n [client, mapName],\n );\n\n const unregister = useCallback(\n async (resolverName: string): Promise<RegisterResult> => {\n setLoading(true);\n setError(null);\n\n try {\n const resolvers = client.getConflictResolvers();\n const result = await resolvers.unregister(mapName, resolverName);\n\n if (result.success) {\n setRegistered((prev) => prev.filter((n) => n !== resolverName));\n } else if (result.error) {\n setError(new Error(result.error));\n }\n\n return result;\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n return { success: false, error: err.message };\n } finally {\n setLoading(false);\n }\n },\n [client, mapName],\n );\n\n const list = useCallback(async (): Promise<ResolverInfo[]> => {\n try {\n const resolvers = client.getConflictResolvers();\n return await resolvers.list(mapName);\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n return [];\n }\n }, [client, mapName]);\n\n return {\n register,\n unregister,\n list,\n loading,\n error,\n registered,\n };\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react","import_react","import_react","error","import_react","import_react","import_react"]}
|