@stream-io/feeds-client 0.2.17 → 0.2.19

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.
Files changed (117) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cjs/index.js +94 -25
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/react-bindings.js +26 -55
  5. package/dist/cjs/react-bindings.js.map +1 -1
  6. package/dist/es/index.mjs +86 -17
  7. package/dist/es/index.mjs.map +1 -1
  8. package/dist/es/react-bindings.mjs +19 -48
  9. package/dist/es/react-bindings.mjs.map +1 -1
  10. package/dist/{index-nq6SDtbt.js → feeds-client-C09giTf1.js} +322 -133
  11. package/dist/feeds-client-C09giTf1.js.map +1 -0
  12. package/dist/{index-BZL77zNq.mjs → feeds-client-CFadXO-B.mjs} +335 -146
  13. package/dist/feeds-client-CFadXO-B.mjs.map +1 -0
  14. package/dist/tsconfig.tsbuildinfo +1 -1
  15. package/dist/types/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.d.ts +2 -32
  16. package/dist/types/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.d.ts.map +1 -1
  17. package/dist/types/common/real-time/StableWSConnection.d.ts +3 -3
  18. package/dist/types/common/real-time/event-models.d.ts +7 -2
  19. package/dist/types/common/real-time/event-models.d.ts.map +1 -1
  20. package/dist/types/common/types.d.ts +1 -0
  21. package/dist/types/common/types.d.ts.map +1 -1
  22. package/dist/types/feed/event-handlers/activity/handle-activity-added.d.ts +4 -3
  23. package/dist/types/feed/event-handlers/activity/handle-activity-added.d.ts.map +1 -1
  24. package/dist/types/feed/event-handlers/activity/handle-activity-updated.d.ts.map +1 -1
  25. package/dist/types/feed/event-handlers/activity-updater.d.ts +44 -0
  26. package/dist/types/feed/event-handlers/activity-updater.d.ts.map +1 -0
  27. package/dist/types/feed/event-handlers/add-aggregated-activities-to-state.d.ts +6 -0
  28. package/dist/types/feed/event-handlers/add-aggregated-activities-to-state.d.ts.map +1 -0
  29. package/dist/types/feed/event-handlers/index.d.ts +3 -1
  30. package/dist/types/feed/event-handlers/index.d.ts.map +1 -1
  31. package/dist/types/feed/event-handlers/{aggregated-feed/handle-aggregated-feed-updated.d.ts → notification-feed/handle-notification-feed-updated.d.ts} +2 -11
  32. package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts.map +1 -0
  33. package/dist/types/feed/event-handlers/notification-feed/index.d.ts +2 -0
  34. package/dist/types/feed/event-handlers/notification-feed/index.d.ts.map +1 -0
  35. package/dist/types/feed/event-handlers/story-feeds/handle-story-feeds-updated.d.ts +15 -0
  36. package/dist/types/feed/event-handlers/story-feeds/handle-story-feeds-updated.d.ts.map +1 -0
  37. package/dist/types/feed/event-handlers/story-feeds/index.d.ts +2 -0
  38. package/dist/types/feed/event-handlers/story-feeds/index.d.ts.map +1 -0
  39. package/dist/types/feed/feed.d.ts +10 -4
  40. package/dist/types/feed/feed.d.ts.map +1 -1
  41. package/dist/types/feeds-client/feeds-client.d.ts +14 -4
  42. package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
  43. package/dist/types/gen/feeds/FeedsApi.d.ts.map +1 -1
  44. package/dist/types/gen/models/index.d.ts +42 -451
  45. package/dist/types/gen/models/index.d.ts.map +1 -1
  46. package/dist/types/utils/throttling/index.d.ts +3 -0
  47. package/dist/types/utils/throttling/index.d.ts.map +1 -0
  48. package/dist/types/utils/throttling/throttle.d.ts +34 -0
  49. package/dist/types/utils/throttling/throttle.d.ts.map +1 -0
  50. package/dist/types/utils/throttling/throttled-get-batched-own-capabilities.d.ts +14 -0
  51. package/dist/types/utils/throttling/throttled-get-batched-own-capabilities.d.ts.map +1 -0
  52. package/package.json +7 -3
  53. package/react-bindings.d.ts +11 -0
  54. package/react-bindings.js +7 -0
  55. package/react-bindings.mjs +11 -0
  56. package/src/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.ts +21 -73
  57. package/src/common/real-time/event-models.ts +8 -2
  58. package/src/common/types.ts +1 -0
  59. package/src/feed/event-handlers/activity/handle-activity-added.ts +18 -12
  60. package/src/feed/event-handlers/activity/handle-activity-updated.ts +12 -16
  61. package/src/feed/event-handlers/activity-updater.ts +15 -0
  62. package/src/feed/event-handlers/add-aggregated-activities-to-state.ts +72 -0
  63. package/src/feed/event-handlers/index.ts +3 -1
  64. package/src/feed/event-handlers/{aggregated-feed/handle-aggregated-feed-updated.ts → notification-feed/handle-notification-feed-updated.ts} +2 -94
  65. package/src/feed/event-handlers/notification-feed/index.ts +1 -0
  66. package/src/feed/event-handlers/story-feeds/handle-story-feeds-updated.ts +122 -0
  67. package/src/feed/event-handlers/story-feeds/index.ts +1 -0
  68. package/src/feed/feed.ts +30 -3
  69. package/src/feeds-client/feeds-client.ts +127 -6
  70. package/src/gen/feeds/FeedsApi.ts +5 -0
  71. package/src/gen/model-decoders/decoders.ts +10 -4
  72. package/src/gen/models/index.ts +75 -834
  73. package/src/test-utils/response-generators.ts +37 -1
  74. package/src/utils/throttling/index.ts +2 -0
  75. package/src/utils/throttling/throttle.ts +123 -0
  76. package/src/utils/throttling/throttled-get-batched-own-capabilities.ts +42 -0
  77. package/dist/index-BZL77zNq.mjs.map +0 -1
  78. package/dist/index-nq6SDtbt.js.map +0 -1
  79. package/dist/types/feed/event-handlers/aggregated-feed/handle-aggregated-feed-updated.d.ts.map +0 -1
  80. package/dist/types/feed/event-handlers/aggregated-feed/index.d.ts +0 -2
  81. package/dist/types/feed/event-handlers/aggregated-feed/index.d.ts.map +0 -1
  82. package/src/feed/event-handlers/activity/activity-marked-utils.test.ts +0 -208
  83. package/src/feed/event-handlers/activity/activity-reaction-utils.test.ts +0 -371
  84. package/src/feed/event-handlers/activity/activity-utils.test.ts +0 -252
  85. package/src/feed/event-handlers/activity/handle-activity-added.test.ts +0 -86
  86. package/src/feed/event-handlers/activity/handle-activity-deleted.test.ts +0 -117
  87. package/src/feed/event-handlers/activity/handle-activity-pinned.test.ts +0 -60
  88. package/src/feed/event-handlers/activity/handle-activity-reaction-added.test.ts +0 -257
  89. package/src/feed/event-handlers/activity/handle-activity-reaction-deleted.test.ts +0 -317
  90. package/src/feed/event-handlers/activity/handle-activity-reaction-updated.test.ts +0 -282
  91. package/src/feed/event-handlers/activity/handle-activity-unpinned.test.ts +0 -95
  92. package/src/feed/event-handlers/activity/handle-activity-updated.test.ts +0 -245
  93. package/src/feed/event-handlers/aggregated-feed/handle-aggregated-feed-updated.test.ts +0 -644
  94. package/src/feed/event-handlers/aggregated-feed/index.ts +0 -1
  95. package/src/feed/event-handlers/bookmark/bookmark-utils.test.ts +0 -521
  96. package/src/feed/event-handlers/bookmark/handle-bookmark-added.test.ts +0 -178
  97. package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.test.ts +0 -188
  98. package/src/feed/event-handlers/bookmark/handle-bookmark-updated.test.ts +0 -196
  99. package/src/feed/event-handlers/comment/handle-comment-added.test.ts +0 -271
  100. package/src/feed/event-handlers/comment/handle-comment-deleted.test.ts +0 -255
  101. package/src/feed/event-handlers/comment/handle-comment-reaction-added.test.ts +0 -329
  102. package/src/feed/event-handlers/comment/handle-comment-reaction-deleted.test.ts +0 -343
  103. package/src/feed/event-handlers/comment/handle-comment-reaction-updated.test.ts +0 -350
  104. package/src/feed/event-handlers/comment/handle-comment-updated.test.ts +0 -267
  105. package/src/feed/event-handlers/comment/utils/update-comment-count.test.ts +0 -322
  106. package/src/feed/event-handlers/feed-member/handle-feed-member-added.test.ts +0 -75
  107. package/src/feed/event-handlers/feed-member/handle-feed-member-removed.test.ts +0 -82
  108. package/src/feed/event-handlers/feed-member/handle-feed-member-updated.test.ts +0 -84
  109. package/src/feed/event-handlers/follow/follow-state-update-queue.test.ts +0 -219
  110. package/src/feed/event-handlers/follow/handle-follow-created.test.ts +0 -250
  111. package/src/feed/event-handlers/follow/handle-follow-deleted.test.ts +0 -268
  112. package/src/feed/event-handlers/follow/handle-follow-updated.test.ts +0 -131
  113. package/src/feed/feed.test.ts +0 -90
  114. package/src/feeds-client/event-handlers/user/handle-user-updated.test.ts +0 -53
  115. package/src/utils/event-triggered-by-connected-user.test.ts +0 -73
  116. package/src/utils/state-update-queue.test.ts +0 -129
  117. package/src/utils/unique-array-merge.test.ts +0 -179
@@ -11,7 +11,11 @@ import type {
11
11
  OwnUser,
12
12
  OwnUserResponse,
13
13
  PinActivityResponse,
14
- UserResponse, UserResponseCommonFields,
14
+ UserResponse,
15
+ UserResponseCommonFields,
16
+ NotificationFeedUpdatedEvent,
17
+ NotificationStatusResponse,
18
+ AggregatedActivityResponse,
15
19
  } from '../gen/models';
16
20
  import { humanId } from 'human-id';
17
21
  import type { EventPayload } from '../types-internal';
@@ -667,3 +671,35 @@ export function generateActivityPinnedEvent(
667
671
  user,
668
672
  };
669
673
  }
674
+
675
+ export const createMockNotificationFeedUpdatedEvent = (
676
+ overrides: Partial<NotificationFeedUpdatedEvent> = {},
677
+ ): NotificationFeedUpdatedEvent => ({
678
+ created_at: new Date(),
679
+ fid: 'user:notification',
680
+ custom: {},
681
+ type: 'feeds.notification_feed.updated',
682
+ ...overrides,
683
+ });
684
+
685
+ export const createMockNotificationStatus = (
686
+ overrides: Partial<NotificationStatusResponse> = {},
687
+ ): NotificationStatusResponse => ({
688
+ unread: 0,
689
+ unseen: 0,
690
+ ...overrides,
691
+ });
692
+
693
+ export const createMockAggregatedActivity = (
694
+ overrides: Partial<AggregatedActivityResponse> = {},
695
+ ): AggregatedActivityResponse => ({
696
+ activity_count: 1,
697
+ created_at: new Date(),
698
+ group: 'test-group',
699
+ user_count_truncated: false,
700
+ score: 1,
701
+ updated_at: new Date(),
702
+ user_count: 1,
703
+ activities: [],
704
+ ...overrides,
705
+ });
@@ -0,0 +1,2 @@
1
+ export * from './throttle';
2
+ export * from './throttled-get-batched-own-capabilities'
@@ -0,0 +1,123 @@
1
+ export type ThrottledCallback = (...args: unknown[]) => unknown;
2
+
3
+ export type ThrottledFunction<T extends unknown[]> = (...args: T) => void;
4
+
5
+ /**
6
+ * Throttle a function so it runs at most once per `timeout` ms.
7
+ *
8
+ * - `leading`: fire immediately when the window opens
9
+ * - `trailing`: remember the latest args/this and fire once when the window closes
10
+ *
11
+ * defaults: `{ leading: true, trailing: false }`
12
+ *
13
+ * notes:
14
+ * - make one throttled instance and reuse it; re-creating it resets internal state
15
+ *
16
+ * @typeParam T - the function type being throttled
17
+ * @param fn - function to throttle
18
+ * @param timeout - minimum time between invocations (ms)
19
+ * @param options - behavior switches
20
+ * @param options.leading - call on the leading edge (default: true)
21
+ * @param options.trailing - call once at the end of the window with the latest args (default: false)
22
+ * @returns a throttled function with the same call signature as `fn`
23
+ *
24
+ * @example
25
+ * const send = (payload: Data) => api.post('/endpoint', payload);
26
+ * const sendThrottled = throttle(send, 2000, { leading: true, trailing: true });
27
+ * // call `sendThrottled` freely; it won’t invoke `send` more than once every 2s
28
+ */
29
+ export const throttle = <T extends unknown[]>(
30
+ fn: (...args: T) => void,
31
+ timeout = 200,
32
+ {
33
+ leading = true,
34
+ trailing = false,
35
+ }: { leading?: boolean; trailing?: boolean } = {},
36
+ ) => {
37
+ let timer: NodeJS.Timeout | null = null;
38
+ let storedArgs: T | null = null;
39
+ let storedThis: unknown = null;
40
+ let lastInvokeTime: number | undefined; // timestamp of last actual invocation
41
+
42
+ const invoke = (args: T, thisArg: unknown) => {
43
+ lastInvokeTime = Date.now();
44
+ fn.apply(thisArg, args);
45
+ };
46
+
47
+ const scheduleTrailing = (delay: number) => {
48
+ if (timer) return;
49
+ timer = setTimeout(() => {
50
+ timer = null;
51
+ if (trailing && storedArgs) {
52
+ invoke(storedArgs, storedThis);
53
+ storedArgs = null;
54
+ storedThis = null;
55
+ }
56
+ }, delay);
57
+ };
58
+
59
+ return {
60
+ throttledFn: function (this: unknown, ...args: T) {
61
+ const now = Date.now();
62
+
63
+ const hasBeenInvoked = lastInvokeTime != null;
64
+
65
+ // if we have never invoked and `leading` is `false`, treat `lastInvokeTime` as now
66
+ if (!hasBeenInvoked && !leading) lastInvokeTime = now;
67
+
68
+ const timeSinceLast = hasBeenInvoked ? now - lastInvokeTime! : timeout;
69
+ const remaining = timeout - timeSinceLast;
70
+
71
+ // capture latest args for possible trailing invocation
72
+ if (trailing) {
73
+ storedArgs = args;
74
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
75
+ storedThis = this;
76
+ }
77
+
78
+ // if enough time has passed, invoke immediately
79
+ if (remaining <= 0) {
80
+ // if there's a pending timer, clear it because we're invoking now
81
+ if (timer) {
82
+ clearTimeout(timer);
83
+ timer = null;
84
+ }
85
+
86
+ // leading: call now
87
+ if (leading) {
88
+ // if trailing is also `true`, we've already stored args above;
89
+ // make sure we don't call the same args twice
90
+ if (trailing) {
91
+ // if the `storedArgs` are exactly the args we're about to call,
92
+ // clear storedArgs to avoid double invocation by trailing (comparing
93
+ // by reference is fine because the `args` array is new each call)
94
+ if (storedArgs === args) {
95
+ storedArgs = null;
96
+ storedThis = null;
97
+ }
98
+ }
99
+ invoke(args, this);
100
+ } else {
101
+ // not leading but trailing: schedule a trailing call after `timeout`
102
+ if (trailing) scheduleTrailing(timeout);
103
+ }
104
+
105
+ return;
106
+ }
107
+
108
+ // not enough time passed: we're in cooldown, so if
109
+ // trailing is requested, ensure a trailing invocation
110
+ // is scheduled at the end of the remaining time
111
+ if (trailing && !timer) {
112
+ scheduleTrailing(remaining);
113
+ }
114
+ // if `trailing` is `false`, we simply drop the call (throttle)
115
+ },
116
+ cancelTimer: () => {
117
+ if (timer) {
118
+ clearTimeout(timer);
119
+ timer = null;
120
+ }
121
+ },
122
+ };
123
+ };
@@ -0,0 +1,42 @@
1
+ import type { FeedsClient } from '@self';
2
+ import type { ThrottledFunction } from './throttle';
3
+
4
+ export type GetBatchedOwnCapabilities = {
5
+ feeds: string[];
6
+ };
7
+
8
+ export type GetBatchedOwnCapabilitiesThrottledCallback = [
9
+ feeds: string[],
10
+ callback: (feedsToClear: string[]) => void | Promise<void>,
11
+ ];
12
+
13
+ export type ThrottledGetBatchedOwnCapabilities =
14
+ ThrottledFunction<GetBatchedOwnCapabilitiesThrottledCallback>;
15
+
16
+ export const DEFAULT_BATCH_OWN_CAPABILITIES_THROTTLING_INTERVAL = 2000;
17
+
18
+ const queuedFeeds: Set<string> = new Set();
19
+
20
+ export function queueBatchedOwnCapabilities(
21
+ this: FeedsClient,
22
+ { feeds }: GetBatchedOwnCapabilities,
23
+ ) {
24
+ for (const feed of feeds) {
25
+ queuedFeeds.add(feed);
26
+ }
27
+
28
+ if (queuedFeeds.size > 0) {
29
+ this.throttledGetBatchOwnCapabilities(
30
+ [...queuedFeeds],
31
+ (feedsToClear: string[]) => {
32
+ for (const feed of feedsToClear) {
33
+ queuedFeeds.delete(feed);
34
+ }
35
+ },
36
+ );
37
+ }
38
+ }
39
+
40
+ export function clearQueuedFeeds() {
41
+ queuedFeeds.clear();
42
+ }