@adventurelabs/scout-core 1.4.21 → 1.4.23

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.
@@ -436,10 +436,16 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
436
436
  }
437
437
  prevHerdIdRef.current = herdId;
438
438
  }, [herdId, options.enabled]);
439
+ // When we request a new page (cursor changed), clear ref so we merge the new response
440
+ useEffect(() => {
441
+ lastAddedCursorRef.current = undefined;
442
+ }, [currentCursor]);
439
443
  useEffect(() => {
440
444
  if (!currentQuery.data || currentQuery.isLoading)
441
445
  return;
442
- if (feedCursorEq(lastAddedCursorRef.current ?? null, currentCursor))
446
+ // Don't skip the first page after reset: only skip when we already have pages for this cursor
447
+ if (pages.length > 0 &&
448
+ feedCursorEq(lastAddedCursorRef.current ?? null, currentCursor))
443
449
  return;
444
450
  setPages((prev) => {
445
451
  const existingPage = prev.find((p) => feedCursorEq(p.cursor, currentCursor));
@@ -447,7 +453,11 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
447
453
  const items = Array.isArray(currentQuery.data?.items)
448
454
  ? currentQuery.data.items
449
455
  : [];
450
- lastAddedCursorRef.current = currentCursor;
456
+ const limit = options.limit || 20;
457
+ // Only mark "last added" for full pages so partial/empty responses don't block a later merge
458
+ if (items.length >= limit) {
459
+ lastAddedCursorRef.current = currentCursor;
460
+ }
451
461
  return [
452
462
  ...prev,
453
463
  { cursor: currentCursor, data: items },
@@ -455,7 +465,7 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
455
465
  }
456
466
  return prev;
457
467
  });
458
- }, [currentQuery.data, currentQuery.isLoading, currentCursor]);
468
+ }, [currentQuery.data, currentQuery.isLoading, currentCursor, pages.length, options.limit]);
459
469
  const loadMore = useCallback(() => {
460
470
  if (currentQuery.data?.hasMore &&
461
471
  currentQuery.data.nextCursor &&
@@ -483,7 +493,9 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
483
493
  items: allItems,
484
494
  isLoading: currentQuery.isLoading && pages.length === 0,
485
495
  isLoadingMore: currentQuery.isLoading && pages.length > 0,
486
- hasMore: currentQuery.data?.hasMore ?? false,
496
+ hasMore: (currentQuery.data?.hasMore ??
497
+ (currentCursor !== null && pages.length > 0)) ??
498
+ false,
487
499
  loadMore,
488
500
  refetch,
489
501
  error: currentQuery.error,
@@ -511,10 +523,15 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
511
523
  }
512
524
  prevDeviceIdRef.current = deviceId;
513
525
  }, [deviceId, options.enabled]);
526
+ // When we request a new page (cursor changed), clear ref so we merge the new response
527
+ useEffect(() => {
528
+ lastAddedCursorRef.current = undefined;
529
+ }, [currentCursor]);
514
530
  useEffect(() => {
515
531
  if (!currentQuery.data || currentQuery.isLoading)
516
532
  return;
517
- if (feedCursorEq(lastAddedCursorRef.current ?? null, currentCursor))
533
+ if (pages.length > 0 &&
534
+ feedCursorEq(lastAddedCursorRef.current ?? null, currentCursor))
518
535
  return;
519
536
  setPages((prev) => {
520
537
  const existingPage = prev.find((p) => feedCursorEq(p.cursor, currentCursor));
@@ -522,7 +539,10 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
522
539
  const items = Array.isArray(currentQuery.data?.items)
523
540
  ? currentQuery.data.items
524
541
  : [];
525
- lastAddedCursorRef.current = currentCursor;
542
+ const limit = options.limit || 20;
543
+ if (items.length >= limit) {
544
+ lastAddedCursorRef.current = currentCursor;
545
+ }
526
546
  return [
527
547
  ...prev,
528
548
  { cursor: currentCursor, data: items },
@@ -530,7 +550,7 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
530
550
  }
531
551
  return prev;
532
552
  });
533
- }, [currentQuery.data, currentQuery.isLoading, currentCursor]);
553
+ }, [currentQuery.data, currentQuery.isLoading, currentCursor, pages.length, options.limit]);
534
554
  const loadMore = useCallback(() => {
535
555
  if (currentQuery.data?.hasMore &&
536
556
  currentQuery.data.nextCursor &&
@@ -558,7 +578,9 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
558
578
  items: allItems,
559
579
  isLoading: currentQuery.isLoading && pages.length === 0,
560
580
  isLoadingMore: currentQuery.isLoading && pages.length > 0,
561
- hasMore: currentQuery.data?.hasMore ?? false,
581
+ hasMore: (currentQuery.data?.hasMore ??
582
+ (currentCursor !== null && pages.length > 0)) ??
583
+ false,
562
584
  loadMore,
563
585
  refetch,
564
586
  error: currentQuery.error,
package/dist/store/api.js CHANGED
@@ -455,7 +455,8 @@ export const scoutApi = createApi({
455
455
  };
456
456
  }
457
457
  const rows = data || [];
458
- const hasMore = rows.length > limit;
458
+ // Full page (rows.length >= limit) means there might be more; only signal hasMore when we have a nextCursor
459
+ const hasMore = rows.length >= limit;
459
460
  const resultRows = hasMore ? rows.slice(0, limit) : rows;
460
461
  const uniqueFilePaths = Array.from(new Set(resultRows.flatMap((row) => {
461
462
  const paths = [];
@@ -498,7 +499,7 @@ export const scoutApi = createApi({
498
499
  : null,
499
500
  }));
500
501
  const last = resultRows[resultRows.length - 1];
501
- const nextCursor = hasMore && last
502
+ const nextCursor = resultRows.length > 0
502
503
  ? {
503
504
  timestamp: last.sort_ts ?? "",
504
505
  id: last.sort_id ?? 0,
@@ -506,7 +507,11 @@ export const scoutApi = createApi({
506
507
  }
507
508
  : null;
508
509
  return {
509
- data: { items, nextCursor, hasMore },
510
+ data: {
511
+ items,
512
+ nextCursor,
513
+ hasMore: nextCursor != null && hasMore,
514
+ },
510
515
  };
511
516
  }
512
517
  catch (err) {
@@ -537,7 +542,8 @@ export const scoutApi = createApi({
537
542
  };
538
543
  }
539
544
  const rows = data || [];
540
- const hasMore = rows.length > limit;
545
+ // Full page (rows.length >= limit) means there might be more; only signal hasMore when we have a nextCursor
546
+ const hasMore = rows.length >= limit;
541
547
  const resultRows = hasMore ? rows.slice(0, limit) : rows;
542
548
  const uniqueFilePaths = Array.from(new Set(resultRows.flatMap((row) => {
543
549
  const paths = [];
@@ -580,7 +586,7 @@ export const scoutApi = createApi({
580
586
  : null,
581
587
  }));
582
588
  const last = resultRows[resultRows.length - 1];
583
- const nextCursor = hasMore && last
589
+ const nextCursor = resultRows.length > 0
584
590
  ? {
585
591
  timestamp: last.sort_ts ?? "",
586
592
  id: last.sort_id ?? 0,
@@ -588,7 +594,11 @@ export const scoutApi = createApi({
588
594
  }
589
595
  : null;
590
596
  return {
591
- data: { items, nextCursor, hasMore },
597
+ data: {
598
+ items,
599
+ nextCursor,
600
+ hasMore: nextCursor != null && hasMore,
601
+ },
592
602
  };
593
603
  }
594
604
  catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.4.21",
3
+ "version": "1.4.23",
4
4
  "description": "Core utilities and helpers for Adventure Labs Scout applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",