Skip to content

Commit fc9f195

Browse files
committed
Revert "chore(KNO-11486): exclude metadata when refetching feed after new message received (#853)"
This reverts commit 1e75952.
1 parent 1e75952 commit fc9f195

9 files changed

Lines changed: 18 additions & 402 deletions

File tree

.changeset/chatty-cars-care.md

Lines changed: 0 additions & 16 deletions
This file was deleted.

packages/client/src/clients/feed/feed.ts

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,7 @@ import {
3333
FeedMessagesReceivedPayload,
3434
FeedRealTimeCallback,
3535
} from "./types";
36-
import {
37-
getFormattedExclude,
38-
getFormattedTriggerData,
39-
mergeAndDedupeArrays,
40-
mergeDateRangeParams,
41-
} from "./utils";
36+
import { getFormattedTriggerData, mergeDateRangeParams } from "./utils";
4237

4338
// Default options to apply
4439
const feedClientDefaults: Pick<FeedClientOptions, "archived" | "mode"> = {
@@ -541,27 +536,19 @@ class Feed {
541536
// Set the loading type based on the request type it is
542537
state.setNetworkStatus(options.__loadingType ?? NetworkStatus.loading);
543538

544-
const mergedOptions = {
545-
...this.defaultOptions,
546-
...mergeDateRangeParams(options),
547-
exclude: mergeAndDedupeArrays(
548-
this.defaultOptions.exclude,
549-
options.exclude,
550-
),
551-
};
552-
553539
// trigger_data should be a JSON string for the API
554540
// this function will format the trigger data if it's an object
555-
// https://docs.knock.app/api-reference/users/feeds/list_items
556-
const formattedTriggerData = getFormattedTriggerData(mergedOptions);
557-
558-
const formattedExclude = getFormattedExclude(mergedOptions);
541+
// https://docs.knock.app/reference#get-feed
542+
const formattedTriggerData = getFormattedTriggerData({
543+
...this.defaultOptions,
544+
...options,
545+
});
559546

560547
// Always include the default params, if they have been set
561548
const queryParams: FetchFeedOptionsForRequest = {
562-
...mergedOptions,
549+
...this.defaultOptions,
550+
...mergeDateRangeParams(options),
563551
trigger_data: formattedTriggerData,
564-
exclude: formattedExclude,
565552
// Unset options that should not be sent to the API
566553
__loadingType: undefined,
567554
__fetchSource: undefined,
@@ -612,8 +599,7 @@ class Feed {
612599

613600
const eventPayload = {
614601
items: response.entries as FeedItem[],
615-
// meta will not be present on the response when __fetchSource is "socket"
616-
metadata: response.meta as FeedMetadata | undefined,
602+
metadata: response.meta as FeedMetadata,
617603
event: feedEventType,
618604
};
619605

@@ -664,13 +650,7 @@ class Feed {
664650
}
665651

666652
// Fetch the items before the current head (if it exists)
667-
this.fetch({
668-
before: currentHead?.__cursor,
669-
__fetchSource: "socket",
670-
// The socket event payload should *always* include metadata,
671-
// but to be safe, only exclude meta from the fetch when it's present
672-
exclude: metadata ? ["meta"] : [],
673-
});
653+
this.fetch({ before: currentHead?.__cursor, __fetchSource: "socket" });
674654
}
675655

676656
private buildUserFeedId() {

packages/client/src/clients/feed/interfaces.ts

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,35 +58,21 @@ export interface FeedClientOptions {
5858
* @default "compact"
5959
*/
6060
mode?: "rich" | "compact";
61-
/**
62-
* Field paths to exclude from the response. Use dot notation for nested fields
63-
* (e.g., "entries.archived_at"). Limited to 3 levels deep.
64-
*/
65-
exclude?: string[];
6661
}
6762

6863
export type FetchFeedOptions = {
6964
__loadingType?: NetworkStatus.loading | NetworkStatus.fetchMore;
7065
__fetchSource?: "socket" | "http";
7166
} & Omit<FeedClientOptions, "__experimentalCrossBrowserUpdates">;
7267

73-
/**
74-
* The final data shape that is sent to the the list feed items endpoint of the Knock API.
75-
*
76-
* @see https://docs.knock.app/api-reference/users/feeds/list_items
77-
*/
68+
// The final data shape that is sent to the API
69+
// Should match types here: https://docs.knock.app/reference#get-feed
7870
export type FetchFeedOptionsForRequest = Omit<
7971
FeedClientOptions,
80-
"trigger_data" | "exclude"
72+
"trigger_data"
8173
> & {
8274
// Formatted trigger data into a string
8375
trigger_data?: string;
84-
/** Fields to exclude from the response, joined by commas. */
85-
exclude?: string;
86-
"inserted_at.gte"?: string;
87-
"inserted_at.lte"?: string;
88-
"inserted_at.gt"?: string;
89-
"inserted_at.lt"?: string;
9076
// Unset options that should not be sent to the API
9177
__loadingType: undefined;
9278
__fetchSource: undefined;

packages/client/src/clients/feed/store.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,7 @@ const initalizeStore = () => {
7373
return {
7474
...state,
7575
items,
76-
// Preserve existing metadata if meta is not provided
77-
// (e.g., when excluded via `exclude` param)
78-
metadata: meta ?? state.metadata,
76+
metadata: meta,
7977
pageInfo: options.shouldSetPage ? page_info : state.pageInfo,
8078
loading: false,
8179
networkStatus: NetworkStatus.ready,

packages/client/src/clients/feed/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export type BindableFeedEvent = FeedEvent | "items.received.*" | "items.*";
5656
export interface FeedEventPayload<T = GenericData> {
5757
event: Omit<FeedEvent, "messages.new">;
5858
items: FeedItem<T>[];
59-
metadata?: FeedMetadata;
59+
metadata: FeedMetadata;
6060
}
6161

6262
export type FeedRealTimeCallback = (resp: FeedResponse) => void;

packages/client/src/clients/feed/utils.ts

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -66,27 +66,3 @@ export function getFormattedTriggerData(options: FeedClientOptions) {
6666

6767
return undefined;
6868
}
69-
70-
export function getFormattedExclude(options: FeedClientOptions) {
71-
if (!options?.exclude?.length) {
72-
return undefined;
73-
}
74-
75-
const fields = options.exclude
76-
.map((field) => field.trim())
77-
.filter((field) => !!field);
78-
79-
return fields.length ? fields.join(",") : undefined;
80-
}
81-
82-
/**
83-
* Merges two arrays, deduplicating values.
84-
* Returns undefined if the merged result is empty.
85-
*/
86-
export function mergeAndDedupeArrays<T>(
87-
array1: T[] | undefined,
88-
array2: T[] | undefined,
89-
): T[] | undefined {
90-
const merged = [...(array1 ?? []), ...(array2 ?? [])];
91-
return merged.length ? [...new Set(merged)] : undefined;
92-
}

packages/client/test/clients/feed/feed.test.ts

Lines changed: 3 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,74 +1253,16 @@ describe("Feed", () => {
12531253
event: "new-message" as const,
12541254
metadata: { total_count: 2, unread_count: 2, unseen_count: 2 },
12551255
data: {
1256-
[feed.referenceId]: {
1256+
client_ref_id: {
12571257
metadata: { total_count: 2, unread_count: 2, unseen_count: 2 },
12581258
},
12591259
},
12601260
};
12611261

12621262
await feed.handleSocketEvent(newMessagePayload);
12631263

1264-
// Should trigger a fetch to get the latest data with exclude: "meta"
1265-
expect(mockApiClient.makeRequest).toHaveBeenCalledWith({
1266-
method: "GET",
1267-
url: "/v1/users/user_123/feeds/01234567-89ab-cdef-0123-456789abcdef",
1268-
params: {
1269-
archived: "exclude",
1270-
mode: "compact",
1271-
exclude: "meta",
1272-
},
1273-
});
1274-
} finally {
1275-
cleanup();
1276-
}
1277-
});
1278-
1279-
test("handles new message socket events without metadata in payload", async () => {
1280-
const { knock, mockApiClient, cleanup } = getTestSetup();
1281-
1282-
try {
1283-
const mockSocketManager = {
1284-
join: vi.fn().mockReturnValue(vi.fn()),
1285-
leave: vi.fn(),
1286-
};
1287-
1288-
// Mock the store response for the feed fetch
1289-
mockApiClient.makeRequest.mockResolvedValue({
1290-
statusCode: "ok",
1291-
body: {
1292-
entries: [],
1293-
page_info: { before: null, after: null },
1294-
meta: { total_count: 1, unread_count: 1, unseen_count: 1 },
1295-
},
1296-
});
1297-
1298-
const feed = new Feed(
1299-
knock,
1300-
"01234567-89ab-cdef-0123-456789abcdef",
1301-
{},
1302-
mockSocketManager as unknown as FeedSocketManager,
1303-
);
1304-
1305-
// Payload lacking metadata for this client's referenceId.
1306-
// This should never happen in practice, but we should handle it gracefully.
1307-
const newMessagePayload = {
1308-
event: "new-message" as const,
1309-
metadata: { total_count: 2, unread_count: 2, unseen_count: 2 },
1310-
data: {},
1311-
};
1312-
1313-
await feed.handleSocketEvent(newMessagePayload);
1314-
1315-
// Should trigger a fetch WITHOUT exclude: "meta" to get badge counts from API
1316-
expect(mockApiClient.makeRequest).toHaveBeenCalledWith({
1317-
method: "GET",
1318-
url: "/v1/users/user_123/feeds/01234567-89ab-cdef-0123-456789abcdef",
1319-
params: {
1320-
archived: "exclude",
1321-
mode: "compact",
1322-
},
1323-
});
1264+
// Should trigger a fetch to get the latest data
1265+
expect(mockApiClient.makeRequest).toHaveBeenCalled();
13241266
} finally {
13251267
cleanup();
13261268
}
@@ -1735,83 +1677,4 @@ describe("Feed", () => {
17351677
}
17361678
});
17371679
});
1738-
1739-
describe("Exclude Option", () => {
1740-
test("converts exclude array to comma-separated string in query params", async () => {
1741-
const { knock, mockApiClient, cleanup } = getTestSetup();
1742-
1743-
try {
1744-
const mockFeedResponse = {
1745-
entries: [],
1746-
meta: { total_count: 0, unread_count: 0, unseen_count: 0 },
1747-
page_info: { before: null, after: null, page_size: 50 },
1748-
};
1749-
1750-
mockApiClient.makeRequest.mockResolvedValue({
1751-
statusCode: "ok",
1752-
body: mockFeedResponse,
1753-
});
1754-
1755-
const feed = new Feed(
1756-
knock,
1757-
"01234567-89ab-cdef-0123-456789abcdef",
1758-
{},
1759-
undefined,
1760-
);
1761-
1762-
await feed.fetch({
1763-
exclude: ["entries.archived_at", "meta.total_count"],
1764-
});
1765-
1766-
expect(mockApiClient.makeRequest).toHaveBeenCalledWith({
1767-
method: "GET",
1768-
url: "/v1/users/user_123/feeds/01234567-89ab-cdef-0123-456789abcdef",
1769-
params: {
1770-
archived: "exclude",
1771-
mode: "compact",
1772-
exclude: "entries.archived_at,meta.total_count",
1773-
},
1774-
});
1775-
} finally {
1776-
cleanup();
1777-
}
1778-
});
1779-
1780-
test("ignores empty exclude array", async () => {
1781-
const { knock, mockApiClient, cleanup } = getTestSetup();
1782-
1783-
try {
1784-
const mockFeedResponse = {
1785-
entries: [],
1786-
meta: { total_count: 0, unread_count: 0, unseen_count: 0 },
1787-
page_info: { before: null, after: null, page_size: 50 },
1788-
};
1789-
1790-
mockApiClient.makeRequest.mockResolvedValue({
1791-
statusCode: "ok",
1792-
body: mockFeedResponse,
1793-
});
1794-
1795-
const feed = new Feed(
1796-
knock,
1797-
"01234567-89ab-cdef-0123-456789abcdef",
1798-
{},
1799-
undefined,
1800-
);
1801-
1802-
await feed.fetch({ exclude: [] });
1803-
1804-
expect(mockApiClient.makeRequest).toHaveBeenCalledWith({
1805-
method: "GET",
1806-
url: "/v1/users/user_123/feeds/01234567-89ab-cdef-0123-456789abcdef",
1807-
params: {
1808-
archived: "exclude",
1809-
mode: "compact",
1810-
},
1811-
});
1812-
} finally {
1813-
cleanup();
1814-
}
1815-
});
1816-
});
18171680
});

packages/client/test/clients/feed/store.test.ts

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -232,32 +232,6 @@ describe("feed store", () => {
232232
const state = store.getState();
233233
expect(state.items).toHaveLength(2); // Should deduplicate
234234
});
235-
236-
test("preserves existing metadata when meta is undefined", () => {
237-
const store = createStore();
238-
239-
// Set initial result with metadata
240-
store.getState().setResult({
241-
entries: mockItems,
242-
meta: mockMetadata,
243-
page_info: mockPageInfo,
244-
});
245-
246-
// Verify initial metadata is set
247-
expect(store.getState().metadata).toEqual(mockMetadata);
248-
249-
// Set new result without meta (simulating exclude param)
250-
store.getState().setResult({
251-
entries: [mockItems[0]!],
252-
meta: undefined,
253-
page_info: mockPageInfo,
254-
});
255-
256-
// Metadata should be preserved
257-
const state = store.getState();
258-
expect(state.metadata).toEqual(mockMetadata);
259-
expect(state.items).toHaveLength(1);
260-
});
261235
});
262236

263237
describe("setMetadata", () => {

0 commit comments

Comments
 (0)