Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions examples/vite/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ if (!apiKey) {
throw new Error('VITE_STREAM_API_KEY is not defined');
}

const sort: ChannelSort = { last_message_at: -1, updated_at: -1 };
const sort: ChannelSort = [
{ field: 'last_message_at', direction: -1 },
{ field: 'updated_at', direction: -1 },
];

// @ts-expect-error ai_generated isn't on LocalMessage's public type yet
const isMessageAIGenerated = (message: LocalMessage) => !!message?.ai_generated;
Expand Down Expand Up @@ -297,7 +300,7 @@ const App = () => {
$or: {
enabled: true,
generate: () => ({
$or: [{ members: { $in: [chatClient.userID!] } }, { type: 'public' }],
$or: [{ members: { $in: [chatClient.userId!] } }, { type: 'public' }],
members: undefined,
}),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {
Channel,
ChannelMemberResponse,
Event,
MessageResponseBase,
MessageResponse,
ReactionResponse,
StreamChat,
UserResponse,
Expand All @@ -16,15 +16,13 @@ import {
import type { SimulationState, SimulationUser } from './types';

type UnknownRecord = Record<string, unknown>;
type EventPayload = Omit<
Partial<Event>,
'channel' | 'member' | 'message' | 'reaction' | 'user'
> & {
type EventPayload = {
channel?: Partial<WebSocketEventTemplateContext['channel']>;
member?: ChannelMemberResponse;
message?: Partial<MessageResponseBase>;
message?: Partial<MessageResponse>;
reaction?: ReactionResponse;
user?: UserResponse;
[key: string]: unknown;
};

const messageTextFragments = [
Expand Down Expand Up @@ -86,7 +84,7 @@ const buildReactionState = ({
}: {
reaction: ReactionResponse;
}): Pick<
MessageResponseBase,
MessageResponse,
'latest_reactions' | 'reaction_counts' | 'reaction_groups' | 'reaction_scores'
> => {
const reactionType = getId(reaction.type) ?? 'love';
Expand All @@ -113,7 +111,10 @@ const buildReactionState = ({
reaction_scores: {
[reactionType]: reactionScore,
},
};
} as unknown as Pick<
MessageResponse,
'latest_reactions' | 'reaction_counts' | 'reaction_groups' | 'reaction_scores'
>;
};

const uniquePush = <T extends string>(items: T[], value: T) => {
Expand Down Expand Up @@ -390,7 +391,7 @@ export const buildFreshWebSocketEventPayload = ({
text,
updated_at: freshContext.createdAt,
user,
},
} as unknown as Partial<MessageResponse>,
message_id: messageId,
user: eventType === 'message.new' ? user : basePayload.user,
};
Expand All @@ -407,13 +408,14 @@ export const buildFreshWebSocketEventPayload = ({
const reaction = {
...baseReaction,
created_at: freshContext.createdAt,
custom: {},
message_id: messageId,
type: reactionType,
updated_at: freshContext.createdAt,
user,
user_id: user.id,
score: reactionScore,
};
} as unknown as ReactionResponse;

return {
...basePayload,
Expand All @@ -430,7 +432,7 @@ export const buildFreshWebSocketEventPayload = ({
updated_at: freshContext.createdAt,
user,
...buildReactionState({ reaction }),
},
} as unknown as Partial<MessageResponse>,
message_id: messageId,
reaction,
user,
Expand Down Expand Up @@ -464,7 +466,7 @@ export const buildFreshWebSocketEventPayload = ({
member,
updated_at: freshContext.createdAt,
user,
},
} as unknown as Partial<MessageResponse>,
user,
};
}
Expand Down Expand Up @@ -494,7 +496,7 @@ export const trackSimulationStateFromPayload = ({
simulationState,
templateContext,
}: {
payload: Event;
payload: EventPayload;
simulationState: SimulationState;
templateContext: WebSocketEventTemplateContext;
}) => {
Expand Down Expand Up @@ -555,12 +557,12 @@ export const emitWebSocketEventPayload = ({
simulationState: SimulationState;
templateContext: WebSocketEventTemplateContext;
}) => {
const emittedPayload = {
const emittedPayload: EventPayload = {
...payload,
type: eventType,
} as Event;
};

client.dispatchEvent(emittedPayload);
client.dispatchEvent(emittedPayload as Event);

trackSimulationStateFromPayload({
payload: emittedPayload,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,21 +120,22 @@ type BuildChannelSeedContext = Omit<WebSocketEventTemplateContext, 'channel'> &
channel: Partial<DebugChannelResponse>;
};

const createFallbackUser = (id: string, createdAt: string): DebugUserResponse => ({
banned: false,
blocked_user_ids: [],
created_at: createdAt,
id,
invisible: false,
language: '',
last_active: createdAt,
name: id,
online: true,
role: 'user',
shadow_banned: false,
teams: [],
updated_at: createdAt,
});
const createFallbackUser = (id: string, createdAt: string): DebugUserResponse =>
({
banned: false,
blocked_user_ids: [],
created_at: createdAt,
id,
invisible: false,
language: '',
last_active: createdAt,
name: id,
online: true,
role: 'user',
shadow_banned: false,
teams: [],
updated_at: createdAt,
}) as unknown as DebugUserResponse;

const getUserId = (user: DebugUserResponse) =>
typeof user.id === 'string' ? user.id : 'debug-user';
Expand All @@ -154,7 +155,7 @@ const createMember = (user: DebugUserResponse): ChannelMemberResponse => {
updated_at: createdAt,
user,
user_id: getUserId(user),
};
} as unknown as ChannelMemberResponse;
};

const getMemberUserId = (member: { user?: unknown; user_id?: unknown }) => {
Expand All @@ -176,7 +177,7 @@ const buildChannel = (
): DebugChannelResponse => {
const createdAt = context.createdAt;

return {
return ({
cid: context.cid,
config: {
automod: 'disabled',
Expand Down Expand Up @@ -253,7 +254,7 @@ const buildChannel = (
type: context.channelType,
updated_at: createdAt,
...overrides,
};
}) as unknown as DebugChannelResponse;
};

const buildMe = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ const firstLikeReactionTimestamp = '2026-02-12T06:39:56.237389Z';
const secondLikeReactionTimestamp = '2026-02-12T06:39:52.237389Z';
const heartReactionTimestamp = '2026-02-12T06:35:58.021196Z';

export const reactionsPreviewMessage: LocalMessage = {
export const reactionsPreviewMessage = {
created_at: new Date('2026-02-12T06:34:40.000000Z'),
deleted_at: null,
deleted_at: undefined,
id: 'settings-preview-message-id',
latest_reactions: [
{
created_at: fireReactionTimestamp,
custom: {},
message_id: 'settings-preview-message-id',
score: 1,
type: 'fire',
Expand All @@ -26,6 +27,7 @@ export const reactionsPreviewMessage: LocalMessage = {
},
{
created_at: firstLikeReactionTimestamp,
custom: {},
message_id: 'settings-preview-message-id',
score: 1,
type: 'like',
Expand All @@ -40,6 +42,7 @@ export const reactionsPreviewMessage: LocalMessage = {
},
{
created_at: secondLikeReactionTimestamp,
custom: {},
message_id: 'settings-preview-message-id',
score: 1,
type: 'like',
Expand All @@ -54,17 +57,19 @@ export const reactionsPreviewMessage: LocalMessage = {
},
{
created_at: heartReactionTimestamp,
custom: {},
message_id: 'settings-preview-message-id',
score: 1,
type: 'heart',
updated_at: heartReactionTimestamp,
user: { id: 'test-user-2' },
user_id: 'test-user-2',
},
] as LocalMessage['latest_reactions'],
] as unknown as LocalMessage['latest_reactions'],
own_reactions: [
{
created_at: fireReactionTimestamp,
custom: {},
message_id: 'settings-preview-message-id',
score: 1,
type: 'fire',
Expand All @@ -74,6 +79,7 @@ export const reactionsPreviewMessage: LocalMessage = {
},
{
created_at: firstLikeReactionTimestamp,
custom: {},
message_id: 'settings-preview-message-id',
score: 1,
type: 'like',
Expand All @@ -83,36 +89,40 @@ export const reactionsPreviewMessage: LocalMessage = {
},
{
created_at: heartReactionTimestamp,
custom: {},
message_id: 'settings-preview-message-id',
score: 1,
type: 'heart',
updated_at: heartReactionTimestamp,
user: { id: 'test-user' },
user_id: 'test-user',
},
] as LocalMessage['own_reactions'],
pinned_at: null,
] as unknown as LocalMessage['own_reactions'],
pinned_at: undefined,
reaction_counts: { fire: 1, heart: 1, like: 2 },
reaction_groups: {
fire: {
count: 1,
first_reaction_at: fireReactionTimestamp,
last_reaction_at: fireReactionTimestamp,
latest_reactions_by: [],
sum_scores: 1,
},
heart: {
count: 1,
first_reaction_at: heartReactionTimestamp,
last_reaction_at: heartReactionTimestamp,
latest_reactions_by: [],
sum_scores: 1,
},
like: {
count: 2,
first_reaction_at: secondLikeReactionTimestamp,
last_reaction_at: firstLikeReactionTimestamp,
latest_reactions_by: [],
sum_scores: 2,
},
} as LocalMessage['reaction_groups'],
} as unknown as LocalMessage['reaction_groups'],
reaction_scores: { fire: 1, heart: 1, like: 2 },
status: 'received',
text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed lectus nibh, rutrum in risus eget, dictum commodo dolor. Donec augue nisi, sollicitudin sed magna ut, tincidunt pretium lorem. ',
Expand All @@ -123,7 +133,7 @@ export const reactionsPreviewMessage: LocalMessage = {
image: 'https://getstream.io/random_svg/?id=preview-user&name=Preview+User',
name: 'Preview User',
},
};
} as unknown as LocalMessage;

export const reactionsPreviewChannelState = {
channel: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const useChannelMembershipState = () => {
const { client } = useChatContext();
const { channel } = useChannelStateContext();
const members = useChannelMembersState(channel);
const membership = members[client.userID!] as ChannelMemberResponse | undefined;
const membership = members[client.userId!] as ChannelMemberResponse | undefined;

const isMember = typeof membership?.channel_role === 'string';
const canJoin = channel.data?.own_capabilities?.includes('join-channel');
Expand All @@ -32,7 +32,7 @@ export const ChannelPreviewOverlay = () => {
const handleJoin = useCallback(async () => {
setJoining(true);
try {
await channel.addMembers([client.userID!]);
await channel.addMembers([client.userId!]);
} catch (error) {
addNotification({
emitter: 'ChannelPreviewOverlay',
Expand All @@ -48,7 +48,7 @@ export const ChannelPreviewOverlay = () => {
} finally {
setJoining(false);
}
}, [addNotification, channel, client.userID]);
}, [addNotification, channel, client.userId]);

if (isMember) return null;

Expand Down
3 changes: 2 additions & 1 deletion examples/vite/src/ChatLayout/ChannelMembersRemoveView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ const toError = (error: unknown) =>
error instanceof Error ? error : new Error('An unknown error occurred');

const getUserDisplayName = (user?: UserResponse) =>
user?.name || user?.username || user?.id || '';
// @ts-expect-error username is not typed
user?.name || user?.custom.username || user?.id || '';

const getMemberDisplayName = (member: ChannelMemberResponse) =>
getUserDisplayName(member.user) || member.user_id || '';
Expand Down
2 changes: 1 addition & 1 deletion examples/vite/src/ChatLayout/Sync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export const ThreadStateSync = () => {
isRestoringThread.current = true;

client
.getThread(threadIdToRestore)
.getThreadAndHydrate(threadIdToRestore)
.then((thread) => {
if (!thread || cancelled) return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ const CustomDeleteMessageAlert = ({
appearance='outline'
className='str-chat__delete-message-alert__delete-button'
data-testid='delete-message-alert-delete-button'
onClick={() => onDelete({ deleteForMe, hardDelete })}
onClick={() => onDelete({ delete_for_me: deleteForMe, hard: hardDelete })}
size='md'
variant='danger'
>
Expand Down
2 changes: 1 addition & 1 deletion examples/vite/src/CustomMessageUi/variants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ const CustomMessageUiMetadata = ({
{messageTextUpdatedAt && (
<div
className='custom-message-ui__metadata-edited-status'
title={messageTextUpdatedAt}
title={messageTextUpdatedAt.toISOString()}
>
Edited
</div>
Expand Down
Loading