Skip to content

Commit 352fff1

Browse files
committed
Attach browser context to client SSE
1 parent 07762fd commit 352fff1

4 files changed

Lines changed: 64 additions & 0 deletions

File tree

‎packages/browser-sdk/src/client.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,7 @@ export class ReflagClient {
13781378
publishableKey: this.publishableKey,
13791379
sdkVersion: this.sdkVersion,
13801380
path: "sse/client",
1381+
context: this.context,
13811382
});
13821383
}
13831384

‎packages/browser-sdk/src/sse.ts‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { SDK_VERSION_HEADER_NAME } from "./config";
2+
import { ReflagContext } from "./context";
23
import { Logger, loggerWithPrefix } from "./logger";
34

45
export type EventSourceLike = {
@@ -16,6 +17,36 @@ export type PubSubMessage = {
1617
[key: string]: any;
1718
};
1819

20+
function withoutUndefinedValues(
21+
attributes: Record<string, string | number | undefined> | undefined,
22+
) {
23+
if (!attributes) return undefined;
24+
25+
const cleaned: Record<string, string | number> = {};
26+
for (const [key, value] of Object.entries(attributes)) {
27+
if (value !== undefined) {
28+
cleaned[key] = value;
29+
}
30+
}
31+
32+
return Object.keys(cleaned).length > 0 ? cleaned : undefined;
33+
}
34+
35+
function serializeContext(context: ReflagContext | undefined) {
36+
if (!context) return undefined;
37+
38+
const payload: Record<string, Record<string, string | number>> = {};
39+
const user = withoutUndefinedValues(context.user);
40+
const company = withoutUndefinedValues(context.company);
41+
const other = withoutUndefinedValues(context.other);
42+
43+
if (user) payload.user = user;
44+
if (company) payload.company = company;
45+
if (other) payload.other = other;
46+
47+
return Object.keys(payload).length > 0 ? JSON.stringify(payload) : undefined;
48+
}
49+
1950
export class AblySSEChannel {
2051
private isOpen = false;
2152
private eventSource: EventSourceLike | null = null;
@@ -31,6 +62,7 @@ export class AblySSEChannel {
3162
private publishableKey?: string,
3263
private sdkVersion?: string,
3364
private path = "sse",
65+
private context?: ReflagContext,
3466
) {
3567
this.logger = loggerWithPrefix(logger, "[SSE]");
3668

@@ -130,6 +162,10 @@ export class AblySSEChannel {
130162
if (this.sdkVersion) {
131163
url.searchParams.append(SDK_VERSION_HEADER_NAME, this.sdkVersion);
132164
}
165+
const serializedContext = serializeContext(this.context);
166+
if (serializedContext) {
167+
url.searchParams.append("context", serializedContext);
168+
}
133169

134170
this.eventSource = this.createEventSource(url.toString()) ?? null;
135171
if (!this.eventSource) {
@@ -233,6 +269,7 @@ export function openAblySSEChannel({
233269
publishableKey,
234270
sdkVersion,
235271
path,
272+
context,
236273
}: {
237274
channel?: string;
238275
channels?: string[];
@@ -243,6 +280,7 @@ export function openAblySSEChannel({
243280
publishableKey?: string;
244281
sdkVersion?: string;
245282
path?: string;
283+
context?: ReflagContext;
246284
}) {
247285
const subscribedChannels = channels ?? (channel ? [channel] : []);
248286
const sse = new AblySSEChannel(
@@ -254,6 +292,7 @@ export function openAblySSEChannel({
254292
publishableKey,
255293
sdkVersion,
256294
path,
295+
context,
257296
);
258297

259298
sse.open();

‎packages/browser-sdk/test/init.test.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ describe("init", () => {
164164
expect(spy.mock.calls[0][0].channels).toEqual([]);
165165
expect(spy.mock.calls[0][0].publishableKey).toBe(KEY);
166166
expect(spy.mock.calls[0][0].sdkVersion).toBe("browser-sdk/test");
167+
expect(spy.mock.calls[0][0].context).toEqual({
168+
user: { id: "foo" },
169+
company: undefined,
170+
other: {},
171+
});
167172

168173
await reflagInstance.stop();
169174
expect(closeChannel).toHaveBeenCalledTimes(1);

‎packages/browser-sdk/test/sse.test.ts‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,25 @@ describe("connection handling", () => {
9696
expect(url.searchParams.get("reflag-sdk-version")).toBe("browser-sdk/test");
9797
});
9898

99+
test("includes context as JSON when provided", async () => {
100+
openAblySSEChannel({
101+
channels: [],
102+
callback: vi.fn(),
103+
logger: testLogger,
104+
sseBaseUrl: sseHost,
105+
path: "sse/client",
106+
context: {
107+
user: { id: 23, name: undefined },
108+
other: {},
109+
},
110+
});
111+
112+
const url = new URL(vi.mocked(window.EventSource).mock.calls[0][0]);
113+
expect(url.searchParams.get("context")).toBe(
114+
JSON.stringify({ user: { id: 23 } }),
115+
);
116+
});
117+
99118
test("passes parsed message envelopes to the callback", async () => {
100119
const callback = vi.fn();
101120
const sse = createSSEChannel(callback);

0 commit comments

Comments
 (0)