Skip to content

Commit

Permalink
Merge branch 'master' into translate
Browse files Browse the repository at this point in the history
  • Loading branch information
varbhat authored Jan 8, 2025
2 parents 96d65b5 + 0478adb commit 73acd08
Show file tree
Hide file tree
Showing 8 changed files with 430 additions and 35 deletions.
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,40 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [8.49.0](https://github.com/GetStream/stream-chat-js/compare/v8.48.0...v8.49.0) (2024-12-23)


### Features

* multi tenancy moderation configuration support ([#1426](https://github.com/GetStream/stream-chat-js/issues/1426)) ([ef8736d](https://github.com/GetStream/stream-chat-js/commit/ef8736db680d43f2be48cfaeeb90754b071fa38b))

## [8.48.0](https://github.com/GetStream/stream-chat-js/compare/v8.47.1...v8.48.0) (2024-12-20)


### Features

* **moderation:** add custom check API ([#1411](https://github.com/GetStream/stream-chat-js/issues/1411)) ([ce204d1](https://github.com/GetStream/stream-chat-js/commit/ce204d169d6f383cfa36853086c891eb6d13a968))

### [8.47.1](https://github.com/GetStream/stream-chat-js/compare/v8.47.0...v8.47.1) (2024-12-18)


### Bug Fixes

* message duplication when some messages have the same creation timestamp ([#1421](https://github.com/GetStream/stream-chat-js/issues/1421)) ([b7b019a](https://github.com/GetStream/stream-chat-js/commit/b7b019afa9bbe4d25c40ef6874f9219172991b7d))
* **search:** missing thread_participants in message ([#1412](https://github.com/GetStream/stream-chat-js/issues/1412)) ([af5cb81](https://github.com/GetStream/stream-chat-js/commit/af5cb81051cc7f1964fb17072fd07a2dd9f0b74b))

## [8.47.0](https://github.com/GetStream/stream-chat-js/compare/v8.46.1...v8.47.0) (2024-12-13)


### Features

* add team to channel template ([#1416](https://github.com/GetStream/stream-chat-js/issues/1416)) ([56bc83e](https://github.com/GetStream/stream-chat-js/commit/56bc83ee94d5f9859ebb24edd5f20f9a3b86aaca))


### Bug Fixes

* revert membership initialization behavior ([#1417](https://github.com/GetStream/stream-chat-js/issues/1417)) ([12aa4af](https://github.com/GetStream/stream-chat-js/commit/12aa4af73cade951dec21ec9b94b343eb36ec296))

### [8.46.1](https://github.com/GetStream/stream-chat-js/compare/v8.46.0...v8.46.1) (2024-12-11)


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stream-chat",
"version": "8.46.1",
"version": "8.49.0",
"description": "JS SDK for the Stream Chat API",
"author": "GetStream",
"homepage": "https://getstream.io/chat/",
Expand Down
7 changes: 3 additions & 4 deletions src/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
AscDesc,
PartialUpdateMemberAPIResponse,
AIState,
MessageOptions,
} from './types';
import { Role } from './permissions';
import { DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE } from './constants';
Expand Down Expand Up @@ -237,6 +238,7 @@ export class Channel<StreamChatGenerics extends ExtendableGenerics = DefaultGene
client_id?: string;
connection_id?: string;
message_filter_conditions?: MessageFilters<StreamChatGenerics>;
message_options?: MessageOptions;
query?: string;
} = {},
) {
Expand Down Expand Up @@ -1720,10 +1722,7 @@ export class Channel<StreamChatGenerics extends ExtendableGenerics = DefaultGene
}
}

this.state.membership = {
...this.state.membership,
...state.membership,
};
this.state.membership = state.membership || {};

const messages = state.messages || [];
if (!this.state.messages) {
Expand Down
60 changes: 54 additions & 6 deletions src/moderation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import {
QueryModerationConfigsFilters,
QueryModerationConfigsSort,
Pager,
CustomCheckFlag,
ReviewQueueItem,
QueryConfigsResponse,
} from './types';
import { StreamChat } from './client';
import { normalizeQuerySort } from './utils';
Expand Down Expand Up @@ -172,20 +175,20 @@ export class Moderation<StreamChatGenerics extends ExtendableGenerics = DefaultG
* Upsert moderation config
* @param {Object} config Moderation config to be upserted
*/
async upsertConfig(config: ModerationConfig = {}) {
async upsertConfig(config: ModerationConfig) {
return await this.client.post<UpsertConfigResponse>(this.client.baseURL + '/api/v2/moderation/config', config);
}

/**
* Get moderation config
* @param {string} key Key for which moderation config is to be fetched
*/
async getConfig(key: string) {
return await this.client.get<GetConfigResponse>(this.client.baseURL + '/api/v2/moderation/config/' + key);
async getConfig(key: string, data?: { team?: string }) {
return await this.client.get<GetConfigResponse>(this.client.baseURL + '/api/v2/moderation/config/' + key, data);
}

async deleteConfig(key: string) {
return await this.client.delete(this.client.baseURL + '/api/v2/moderation/config/' + key);
async deleteConfig(key: string, data?: { team?: string }) {
return await this.client.delete(this.client.baseURL + '/api/v2/moderation/config/' + key, data);
}

/**
Expand All @@ -199,7 +202,7 @@ export class Moderation<StreamChatGenerics extends ExtendableGenerics = DefaultG
sort: QueryModerationConfigsSort,
options: Pager = {},
) {
return await this.client.post(this.client.baseURL + '/api/v2/moderation/configs', {
return await this.client.post<QueryConfigsResponse>(this.client.baseURL + '/api/v2/moderation/configs', {
filter: filterConditions,
sort,
...options,
Expand Down Expand Up @@ -255,4 +258,49 @@ export class Moderation<StreamChatGenerics extends ExtendableGenerics = DefaultG
options,
});
}

/**
*
* @param {string} entityType string Type of entity to be checked E.g., stream:user, stream:chat:v1:message, or any custom string
* @param {string} entityID string ID of the entity to be checked. This is mainly for tracking purposes
* @param {string} entityCreatorID string ID of the entity creator
* @param {object} moderationPayload object Content to be checked for moderation. E.g., { texts: ['text1', 'text2'], images: ['image1', 'image2']}
* @param {Array} moderationPayload.texts array Array of texts to be checked for moderation
* @param {Array} moderationPayload.images array Array of images to be checked for moderation
* @param {Array} moderationPayload.videos array Array of videos to be checked for moderation
* @param {Array<CustomCheckFlag>} flags Array of CustomCheckFlag to be passed to flag the entity
* @returns
*/
async addCustomFlags(
entityType: string,
entityID: string,
entityCreatorID: string,
moderationPayload: {
images?: string[];
texts?: string[];
videos?: string[];
},
flags: CustomCheckFlag[],
) {
return await this.client.post<{ id: string; item: ReviewQueueItem; status: string } & APIResponse>(
this.client.baseURL + `/api/v2/moderation/custom_check`,
{
entity_type: entityType,
entity_id: entityID,
entity_creator_id: entityCreatorID,
moderation_payload: moderationPayload,
flags,
},
);
}

/**
* Add custom flags to a message
* @param {string} messageID Message ID to be flagged
* @param {Array<CustomCheckFlag>} flags Array of CustomCheckFlag to be passed to flag the message
* @returns
*/
async addCustomMessageFlags(messageID: string, flags: CustomCheckFlag[]) {
return await this.addCustomFlags(MODERATION_ENTITY_TYPES.message, messageID, '', {}, flags);
}
}
8 changes: 3 additions & 5 deletions src/thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,17 +354,15 @@ export class Thread<SCG extends ExtendableGenerics = DefaultGenerics> {
sortedArray: replies,
sortDirection: 'ascending',
selectValueToCompare: (reply) => reply.created_at.getTime(),
selectKey: (reply) => reply.id,
});

const actualIndex =
replies[index]?.id === message.id ? index : replies[index - 1]?.id === message.id ? index - 1 : null;

if (actualIndex === null) {
if (replies[index]?.id !== message.id) {
return;
}

const updatedReplies = [...replies];
updatedReplies.splice(actualIndex, 1);
updatedReplies.splice(index, 1);

this.state.partialNext({
replies: updatedReplies,
Expand Down
152 changes: 149 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1718,6 +1718,10 @@ export type MessageFilters<StreamChatGenerics extends ExtendableGenerics = Defau
}
>;

export type MessageOptions = {
include_thread_participants?: boolean;
};

export type PrimitiveFilter<ObjectType> = ObjectType | null;

export type QueryFilter<ObjectType = string> = NonNullable<ObjectType> extends string | number | boolean
Expand Down Expand Up @@ -2743,6 +2747,7 @@ export type SearchPayload<StreamChatGenerics extends ExtendableGenerics = Defaul
connection_id?: string;
filter_conditions?: ChannelFilters<StreamChatGenerics>;
message_filter_conditions?: MessageFilters<StreamChatGenerics>;
message_options?: MessageOptions;
query?: string;
sort?: Array<{
direction: AscDesc;
Expand Down Expand Up @@ -2975,6 +2980,7 @@ export type CampaignData = {
custom?: {};
id?: string;
members?: string[];
team?: string;
};
create_channels?: boolean;
deleted_at?: string;
Expand Down Expand Up @@ -3419,6 +3425,14 @@ export type ReviewQueueItem = {
updated_at: string;
};

export type CustomCheckFlag = {
type: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
custom?: Record<string, any>[];
labels?: string[];
reason?: string;
};

export type SubmitActionOptions = {
ban?: {
channel_ban_only?: boolean;
Expand Down Expand Up @@ -3457,6 +3471,8 @@ export type QueryModerationConfigsFilters = QueryFilters<
created_at?: PrimitiveFilter<string>;
} & {
updated_at?: PrimitiveFilter<string>;
} & {
team?: string;
}
>;

Expand Down Expand Up @@ -3526,14 +3542,35 @@ export type ReviewQueueResponse = {
prev?: string;
};

export type ModerationConfig = {};
export type ModerationConfig = {
key: string;
ai_image_config?: AIImageConfig;
ai_text_config?: AITextConfig;
ai_video_config?: AIVideoConfig;
automod_platform_circumvention_config?: AutomodPlatformCircumventionConfig;
automod_semantic_filters_config?: AutomodSemanticFiltersConfig;
automod_toxicity_config?: AutomodToxicityConfig;
block_list_config?: BlockListConfig;
team?: string;
};

export type ModerationConfigResponse = ModerationConfig & {
created_at: string;
updated_at: string;
};

export type GetConfigResponse = {
config: ModerationConfig;
config: ModerationConfigResponse;
};

export type QueryConfigsResponse = {
configs: ModerationConfigResponse[];
next?: string;
prev?: string;
};

export type UpsertConfigResponse = {
config: ModerationConfig;
config: ModerationConfigResponse;
};

export type ModerationFlagOptions = {
Expand All @@ -3558,3 +3595,112 @@ export type AIState =
| 'AI_STATE_THINKING'
| 'AI_STATE_GENERATING'
| (string & {});

export type ModerationActionType = 'flag' | 'shadow' | 'remove' | 'bounce' | 'bounce_flag' | 'bounce_remove';

export type AutomodRule = {
action: ModerationActionType;
label: string;
threshold: number;
};

export type BlockListRule = {
action: ModerationActionType;
name?: string;
};

export type BlockListConfig = {
enabled: boolean;
rules: BlockListRule[];
async?: boolean;
};

export type AutomodToxicityConfig = {
enabled: boolean;
rules: AutomodRule[];
async?: boolean;
};

export type AutomodPlatformCircumventionConfig = {
enabled: boolean;
rules: AutomodRule[];
async?: boolean;
};

export type AutomodSemanticFiltersRule = {
action: ModerationActionType;
name: string;
threshold: number;
};

export type AutomodSemanticFiltersConfig = {
enabled: boolean;
rules: AutomodSemanticFiltersRule[];
async?: boolean;
};

export type AITextSeverityRule = {
action: ModerationActionType;
severity: 'low' | 'medium' | 'high' | 'critical';
};

export type AITextRule = {
label: string;
action?: ModerationActionType;
severity_rules?: AITextSeverityRule[];
};

export type AITextConfig = {
enabled: boolean;
rules: AITextRule[];
async?: boolean;
profile?: string;
severity_rules?: AITextSeverityRule[]; // Deprecated: use rules instead
};

export type AIImageRule = {
action: ModerationActionType;
label: string;
min_confidence?: number;
};

export type AIImageConfig = {
enabled: boolean;
rules: AIImageRule[];
async?: boolean;
};

export type AIVideoRule = {
action: ModerationActionType;
label: string;
min_confidence?: number;
};

export type AIVideoConfig = {
enabled: boolean;
rules: AIVideoRule[];
async?: boolean;
};

export type VelocityFilterConfigRule = {
action: 'flag' | 'shadow' | 'remove' | 'ban';
ban_duration?: number;
cascading_action?: 'flag' | 'shadow' | 'remove' | 'ban';
cascading_threshold?: number;
check_message_context?: boolean;
fast_spam_threshold?: number;
fast_spam_ttl?: number;
ip_ban?: boolean;
shadow_ban?: boolean;
slow_spam_ban_duration?: number;
slow_spam_threshold?: number;
slow_spam_ttl?: number;
};

export type VelocityFilterConfig = {
cascading_actions: boolean;
enabled: boolean;
first_message_only: boolean;
rules: VelocityFilterConfigRule[];
async?: boolean;
};
Loading

0 comments on commit 73acd08

Please sign in to comment.